TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
Session Clear()与 Flush() 解释1 n: U$ t3 L! |# d
1.Clear 方法
6 ?* t2 [ R% z; p' N 无论是Load 还是 Get 都会首先查找缓存(一级缓存) 如果没有,才会去数据库查找,调用Clear() 方法,可以强制清除Session缓存。
, F; s* L9 N5 \7 b/ j2 m, v例:% J1 d8 {& I3 g/ Z, a- l, {& ?! K' b: T
- public void testClear(){
6 X8 ~6 O5 F4 C* ^+ ] - Session session = hibernateUitl.getSessionFactory().getCurrentSession();
* L5 K$ O% p1 T# B X$ X! D) r - session.beginTransaction();
. `# D/ h) X) N8 C* | - Teacher t = (Teacher) session.get(Teacher.class, 3);
, V# S" w/ s; Z6 l+ O6 j6 U - System.out.println(t.getName());# @; K6 I: a( R T1 K
- Teacher t2 = (Teacher) session.get(Teacher.class, 3);0 T% A3 h) u- t$ A" S$ m" Y" c) [
- System.out.println(t2.getName());0 f4 T! E5 P5 I, j% Y" C' m$ _, D
- session.getTransaction().commit();
; `) U7 Y N! d* i$ ]1 o: V - }6 k; d% h) H( m. r8 g3 U
复制代码 这里虽然用了2个get方法(get方法会立即执行sql语句),但因为第一次执行了会缓存一个ID为3的实体,所以虽然有2个get方法只执行一次SQL语句。
3 u/ h; O* R, G$ S$ _( i! ^- public void testClear(){1 n1 e$ U% Y5 v9 _9 |9 K x
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();
/ I. D" x6 D9 i% O" e - session.beginTransaction();
+ u7 I: a: Y% A9 N1 \8 n$ g - Teacher t = (Teacher) session.get(Teacher.class, 3);
& i8 R8 Z% t5 S: ?, F* H - System.out.println(t.getName());2 O: q: r/ q; F! \
- session.clear();//这里不clear只会执行一次sql语句,有clear会执行2次; H. p0 Y: f. ]- ]- @
- Teacher t2 = (Teacher) session.get(Teacher.class, 3);
& u' q4 V U0 b# \1 Y3 y' O - System.out.println(t2.getName());4 t. l8 A$ I( O& \6 X
- session.getTransaction().commit();0 d$ J$ v+ W' v9 Q
- }+ s8 F5 f D) x8 [% n7 l
复制代码
% ]+ Y8 B6 Z, L/ ]0 c4 Z ^! F这里在第2次get前执行session.clear(),我们把hibernate show_sql 出来,它就会执行2次sql语句了。
/ t! a. {5 g1 ]- c7 G- n所以session.clear()会清除缓存。1 g5 L5 m m. t% W$ B( @* ` V" ?
2.Flush方法5 U3 G( I( W* h" i- l
可以强制进行从内存到数据库的同步。
7 V; D$ `$ h. S+ N2 g例:
$ T/ W3 e" |! ~0 ^5 I* B' h- @Test+ f6 \) j) C1 \7 S+ T9 g
- /**
2 [, g9 n" J8 t/ I6 G - * flush 强制与数据库同步, _; K/ F5 T+ y! b+ i
- */
! D8 p" n N# O+ W: B% G& {+ P) x - public void testFlush(){
- ^% c- _ k) N8 M5 `# Y - Session session = HibernateUitl.getSessionFactory().getCurrentSession();8 V) k; x y; u U- i
- session.beginTransaction();
( A8 X' l3 Q" j- h! N - Teacher t = (Teacher) session.get(Teacher.class, 3);
' g$ v. {' W" f- [$ e - t.setName("yyy");. L, o4 Z! o; d
- , {+ ?; U8 u- l
- t.setName("yyyyy");9 d* F% a2 P" {2 L
- session.getTransaction().commit();9 g5 x1 d$ `, P" a M e
- }4 F2 s# ~' K5 x( P" t3 P
* Z& x9 m1 l: z; }- Z) u2 i5 ` j/ M3 G6 u
复制代码 看这段代码,我们setName() 2次, 但程序只会更改数据库一次,在commit时。
" C. Z( [0 s& Z0 M- g% m- @Test" C' F- s9 {8 h$ r- v" c
- /**1 g! p' z9 a0 N& x: }1 J
- * flush 强制与数据库同步, [+ Q7 J- C8 l; d6 s/ P: w
- */ J# x& u1 `: u" i- K
- public void testFlush(){: D' [( `# U& Y$ Q: E
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();
7 }- ^6 h. ]* o - session.beginTransaction();. |1 D- K7 m9 J1 G
- Teacher t = (Teacher) session.get(Teacher.class, 3);: e* i- {3 A( |4 P8 J% h* W, J/ _
- t.setName("yyy");( S' h+ X) W- y8 [
- session.flush();//有flush会执行2次UPDAE,没有会只执行一次1 s$ E+ ]; ?- v: u+ |
- t.setName("yyyyy");
3 k) G0 f+ Q6 I3 A - session.getTransaction().commit();$ b/ k( S- ?) A7 W6 v% f; g
- }
1 J h% f6 j5 F8 }
$ X; h$ @; T; ~; q4 d& C- & u! Y K" m. f6 ]
复制代码
' L, I5 [8 D" [" m4 W
' p1 \! |+ s2 t1 C我们在第2次setName()时 执行session.flush().- G( g9 G7 S" c8 c
再看hibernate 执行的sql 语句. t! r3 ~7 n) L' y
- Hibernate:
* I- E8 Q$ @; t" o7 O - update4 t2 d- y9 _! @8 ?* Q
- Teacher
) p* f5 ~9 P# K, m - set
! b/ f" g4 A/ D2 q - birthday=?,1 N1 z7 V0 {( V# r8 l# \2 ~0 b
- name=?,
" e& n# P8 z. q7 z0 k - title=? - K" m) S, k8 Q9 V
- where
# n( V2 i/ W* {, ]' A - id=?
# G. T" g) S6 e6 G; ]: s - Hibernate: $ x" b8 c# q( R e$ |
- update
/ x( A) w& a8 _* C' T, I I7 }% i - Teacher
& D5 _" s5 v9 K3 U# g8 R" g - set! z2 g. K: h( c. f+ @
- birthday=?,
2 ~; f; p+ B* q4 k9 F) C - name=?,
. z. Q0 z+ P* Z' B% G7 V" z* i' N; T - title=?
4 n! n* G3 w9 u! Y' ]) K8 U - where
" D* F& o. [3 B' ~- e - id=?
& X" i% U6 ]- N! q4 Q0 T - : A8 Z6 d5 d8 x8 g+ T6 |" G
- 4 N k/ K8 h5 ~' F- K; s% F, k7 H
复制代码
% ~/ y- Q) R" X, g7 ~, W9 M+ d% R, i# R, R; _9 J3 @$ f
执行了2次Update
) t/ G; j7 f! U6 S3 y/ _5 }$ \5 B
所以看出来flush方法会强制与数据库同步。 |1 T+ L1 R0 v# ?$ M, B
- U9 Z, A6 F {, u7 e" }" u. \
4 K+ k- N& h& q8 K$ |6 Y2 ^
Flush方法是可以设置的,也就是fulsh什么时候执行是可以设置的2 J/ J. i1 v3 K5 C. ?* x
5 A4 E3 R/ G7 w/ K' d1 m/ j 在session.beginTransaction前设置FlushMode
* e+ T1 e- [% \. t
8 Z& Q7 r7 h7 j3 u& `* F2 E2 xsession.setFlushMode(FlushMode.Always|AUTO|COMMIT|NEVER|MANUAL)3 `1 l2 X$ X7 P8 Q7 N
' k' L, ~. y9 b- w7 IFlushMode有5个值可选
4 i) F3 d" Y. L% [( X& s0 m* }
( S' _: A- B# Y. M. uAlways:任何代码都会Flush
3 u3 _( y* u7 i S# k6 sAUTO:默认方式–自动
0 C& }5 e, y8 A: P5 ]; Q$ F I( x6 uCommit:COMMIT时
9 l; P( y" k2 G8 A9 SNever:始终不1 B8 j* t6 B" }- H# q
MANUAL:手动方式
- Z* H5 `: u! }4 m8 T# T
6 [! T C8 w; i设置FlushMode 有个好处是可以节省开销,比如默认session只做查询时,就可以不让他与数据库同步了。, B& `( [0 a) R! v6 `/ Q4 v
================================================================' s; z& e- E; S+ u. R
我说一下一些需要注意的信息:$ S* a3 V( r! E+ U
" o5 \! N/ m7 n9 \$ ]1 session.clear()的作用是只清除session中的缓存数据,但不管缓存与数据库的同步。, c) T4 F) E8 V' K; i
6 b, g3 U8 L; N) y
比如,你执行了% t, k3 w2 ^8 B- U3 G
. s D: d" {' e0 D& U6 h4 Y4 Y3 @Po po = new Po();4 J" K# S. Q5 b7 S6 q+ D
session.save(po),
; U" a/ d: T% T* e$ X# e) E
/ }* I P# t: k$ W/ h2 [2 `之后马上执行session.clear(),在事务结束的时候,这条数据是不会被持久化到数据库中的,因为一般缓存是在事务提交的时候进行清理的,当在清理缓存前就把缓存给清除了,自然就不会同步到数据库了。不过这个也有例外的情况,就是当对象使用native生成器来生成主键id时,当执行session.save()方法时,就会立马往数据库插入一条数据,这时候执行session.clear()也不会影响了。. o% Z$ ^0 _" u# Z+ X( q9 D2 @
. [( m: x1 \. k5 n
2 当更新或者保存大批量数据的时候,可以每固定数量的时候,进行清理缓存,同时清除缓存:
, p6 O& T7 L+ Y3 E0 _3 c, H/ f3 K) [' q% G0 I# ~ c; X6 n5 [
for (int i = 0; i < 1000;i ++){
: ]5 {0 N3 f2 Y) s8 \: |6 j& C0 S
if (i /20 == 0) {, A$ T9 r1 K, s( Q2 Q* _& g4 t
# S' H( }: ~' R) f; G
session.flush();; d4 U3 |$ B, L: z
, g! J6 k) a/ t$ i; o6 F session.clear();: @+ x6 A9 [9 q8 w5 }1 [
}
l- {& M, o9 t}) q4 I7 b. Y) C+ z% K
0 Z) u3 K4 i" u2 j2 C. ?$ a
因为把大量的对象放到session缓存中会浪费大量的内容空间。# y& Q& k r+ M% q
+ S3 ]$ P ^; z& v' P% s% v3 Q7 c9 R# u
3 执行完session.flush()时,并不意味着数据就肯定持久化到数据库中的,因为事务控制着数据库,如果事务提交失败了,缓存中的数据还是照样会被回滚的。
* U6 Q3 f; F. l/ C7 }4 J2 j' w# A+ U t4 o( W
0 d" y( n; ^7 }/ P |
|