TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
Session Clear()与 Flush() 解释
6 G# w- l- c: W& N& P- y* H! a1.Clear 方法; G3 j# W# a% a+ l1 J
无论是Load 还是 Get 都会首先查找缓存(一级缓存) 如果没有,才会去数据库查找,调用Clear() 方法,可以强制清除Session缓存。! c' r) X+ [9 h C
例:# w1 F& {6 `! ^5 p- f. A& Q
- public void testClear(){
8 }. X- S9 \) t; m& ` - Session session = hibernateUitl.getSessionFactory().getCurrentSession();
/ o9 ^# I/ a2 e- u A+ `- M/ l - session.beginTransaction(); u, c. k" N* M* V; H9 u
- Teacher t = (Teacher) session.get(Teacher.class, 3);
, z3 r, i- j- s( W. ^( Y - System.out.println(t.getName());1 n8 S3 j8 J' f$ G( |" S/ x! u5 |! s
- Teacher t2 = (Teacher) session.get(Teacher.class, 3);
( w, J& M' x$ q& H+ v9 U - System.out.println(t2.getName());
0 i) d4 c5 d) E7 _( S - session.getTransaction().commit();
+ S; g& e. ?9 E - }! ^0 ]4 s8 U" j7 `, a
复制代码 这里虽然用了2个get方法(get方法会立即执行sql语句),但因为第一次执行了会缓存一个ID为3的实体,所以虽然有2个get方法只执行一次SQL语句。
0 W+ K$ b0 k$ P- public void testClear(){- X1 y/ W; O p. v" }, y
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();* `5 j' _6 N+ ?! s8 x9 G, [
- session.beginTransaction();. _7 z) F& M9 j
- Teacher t = (Teacher) session.get(Teacher.class, 3);
! s( w/ M5 O6 V |7 B - System.out.println(t.getName());. W0 B- U+ n4 t
- session.clear();//这里不clear只会执行一次sql语句,有clear会执行2次
3 M1 `: E" A0 V - Teacher t2 = (Teacher) session.get(Teacher.class, 3);( [- e& x# b/ v8 P& c) w/ Z6 x
- System.out.println(t2.getName());
7 G0 H' l8 G6 e! ]% ~ - session.getTransaction().commit();4 I6 C! ^- P$ A4 _: r2 P! H/ H
- }
$ u+ h; J2 A h0 G5 t
复制代码
5 O, P1 |0 j' a1 N这里在第2次get前执行session.clear(),我们把hibernate show_sql 出来,它就会执行2次sql语句了。
. l/ O2 `5 O% \所以session.clear()会清除缓存。2 z( s0 b. Z" A0 }( {# p' }
2.Flush方法: f0 U* U1 }: ?: t
可以强制进行从内存到数据库的同步。5 J9 ?* V# u3 }& l9 |& K0 L* R' Y
例:
/ b) y0 ]- f' q& k3 w- @Test
' B0 L+ g5 s* o+ e* H - /**
% B: D( {! h' P - * flush 强制与数据库同步
- y v: B* }9 ? - */! A0 U3 t5 O- W6 P% e+ j
- public void testFlush(){
8 `' n) [+ c6 E0 x. x$ {2 c: F - Session session = HibernateUitl.getSessionFactory().getCurrentSession();
$ q$ q i/ O( P. O+ n - session.beginTransaction();
1 X1 \2 A: L: Z1 I1 C1 F - Teacher t = (Teacher) session.get(Teacher.class, 3);; ~+ T$ Z3 d7 d( b7 @2 I
- t.setName("yyy");
7 W# l$ L! b! s3 A! r5 q - 1 C2 D, W4 m/ ~1 T3 y8 g: n9 r
- t.setName("yyyyy");
# h' ^' }0 G+ S. ]& q6 c! T Z% H; j - session.getTransaction().commit();
% }* E& u" g" f& `6 P# k# X% G - } t5 F1 E! |+ I7 v2 r8 l
* h" H$ h. ~ J; |0 \ E% f+ N- 6 f% q% f3 G/ Y9 z
复制代码 看这段代码,我们setName() 2次, 但程序只会更改数据库一次,在commit时。4 A; y7 Y. [: Z( g. J
- @Test6 W( a0 M. H$ m% Y
- /**5 v) N- t* f1 `4 u. O1 w! n
- * flush 强制与数据库同步
. n8 B- U; A4 l; t8 v - */7 w* ^' Z$ L Y% q4 |
- public void testFlush(){
$ t* C! W& x( s+ C- c0 S2 [ - Session session = HibernateUitl.getSessionFactory().getCurrentSession();
, R" ?. v# K/ U1 R - session.beginTransaction();8 |( q& E) C# j: y3 i' Y- e& b. F
- Teacher t = (Teacher) session.get(Teacher.class, 3);
, y5 X2 o, l3 p9 u7 H! c - t.setName("yyy");
1 E$ E$ H# H) }& T - session.flush();//有flush会执行2次UPDAE,没有会只执行一次3 ~' P8 m; M4 D1 _
- t.setName("yyyyy");6 w1 K7 H; |3 i: H4 L9 |- }* @
- session.getTransaction().commit();
5 l# \* r6 F( j2 P0 ^! e A7 ^# i - }
9 p% x: U) w3 E' w) |; F - # ^6 G6 Y1 T1 ]% j
- 1 W8 {4 y# U( Z' W( Y9 d
复制代码
% p: h0 U5 A( G+ g& U u; A3 ~& q: M% m5 r1 w
我们在第2次setName()时 执行session.flush().
- R* b2 {& j2 O6 Z( c; `再看hibernate 执行的sql 语句
) q, ^+ d5 M( A. z9 I; l- Hibernate: ! ]% S# u: ]; b+ [- F y3 C
- update, Q2 O( X* k7 o; o7 \
- Teacher % ]# v' Y- _1 g/ I3 u. w
- set' \1 y( J6 o/ d1 k! q2 B
- birthday=?,
; U2 N: A* h' t - name=?,# f$ H9 V! |- }1 Y3 i+ L
- title=? 6 V" h7 ]- G# b1 \& o
- where
0 A( K1 r, w" g3 x - id=?
- `( ]0 H, ^6 b - Hibernate:
5 z5 ^2 j. t- C! r4 ~ - update
& m# E. H2 |! x, k - Teacher $ \' R9 [" u# H/ t7 f- }! S, \
- set! c7 }0 o" y+ V. N w% \
- birthday=?,1 Y" `7 z* _+ C- b& a. q* p
- name=?,
9 d, u5 K; k3 f6 q& z5 E - title=?
T; g- h& `4 w- E2 x6 i - where8 R9 k* d% |2 }- B
- id=?* F) p4 J" ^, g7 `! u1 O
j% e* Y7 m2 f( j9 T$ D' i
1 y; [) ~9 r3 X8 o/ x! n: B
复制代码
y6 L) D% ^. E& n6 f
5 V0 q% T: b' n0 G9 C3 ~7 U执行了2次Update
) X# f" b4 o, |# m& J) x* Z
- N- F) p" k" O' Q! W( ~所以看出来flush方法会强制与数据库同步。
( |9 P$ h% O% `% }6 {
" ?% Z$ Y) x( O7 B0 l, \) I. P6 C% P7 S U8 \( ]/ Z1 o- q
Flush方法是可以设置的,也就是fulsh什么时候执行是可以设置的* B/ c3 s2 K6 D3 R6 u) w2 H
" a# K; V1 q' h* c2 r3 S' r2 }. s& K$ ^+ {
在session.beginTransaction前设置FlushMode
, P8 }0 P$ H* E$ [9 t8 J2 X. w M/ W+ L# d: T u. l2 D2 j# Z
session.setFlushMode(FlushMode.Always|AUTO|COMMIT|NEVER|MANUAL)' C2 `) N3 X: Q
. D8 k2 Q* ^1 ]8 GFlushMode有5个值可选% I2 {0 d! H. L. ]" j" l. T1 B7 l
$ `+ c {8 |7 T2 ]$ \1 tAlways:任何代码都会Flush
E9 N: t" C( u! X, \9 W5 bAUTO:默认方式–自动& U; c% U5 i+ G; b9 ^% T: [
Commit:COMMIT时4 V5 e% l9 u# C7 a/ r+ O" d
Never:始终不
: z; @9 n, j* R. E- q" k, R2 JMANUAL:手动方式
7 T5 p' Y: v4 D. f+ r
1 M* c# [( X5 X E; F设置FlushMode 有个好处是可以节省开销,比如默认session只做查询时,就可以不让他与数据库同步了。 @ ~: W" X# J
================================================================+ f9 c- I% @ m: N
我说一下一些需要注意的信息:% k8 J& v3 v- K+ e" B- `/ X4 j
/ s- h4 R/ H- b j& l
1 session.clear()的作用是只清除session中的缓存数据,但不管缓存与数据库的同步。
4 z, A- ?/ b8 Z+ y8 F4 e
2 J; `2 B& s! ?4 p比如,你执行了
% R8 [! n ^- Y+ u8 d$ t, K7 [3 K. k' u
Po po = new Po();
{8 |% W# f! C; esession.save(po)," V% V- h1 k' z; e5 r# x8 S
# h6 M' E& \2 e7 ^( z
之后马上执行session.clear(),在事务结束的时候,这条数据是不会被持久化到数据库中的,因为一般缓存是在事务提交的时候进行清理的,当在清理缓存前就把缓存给清除了,自然就不会同步到数据库了。不过这个也有例外的情况,就是当对象使用native生成器来生成主键id时,当执行session.save()方法时,就会立马往数据库插入一条数据,这时候执行session.clear()也不会影响了。
. l) C; U# m# Y. H: ^2 t8 M+ M: T
' `9 M* z+ p4 l+ Z( v2 当更新或者保存大批量数据的时候,可以每固定数量的时候,进行清理缓存,同时清除缓存:
. ], \# w+ k4 ]( x2 @6 k- H1 X& |8 h8 h6 E1 v' i' y
for (int i = 0; i < 1000;i ++){9 Q" T3 t+ o& Y. v
: S: `' p0 X: _if (i /20 == 0) {
5 y: e+ S$ r8 N) U3 I- x0 J) \% o" {
session.flush();
( [% P% g" J1 P W# z; @" N. w" V* ]% W) `8 N+ L
session.clear();
y* J& B; u' H7 S2 |3 D/ K. ?}
- u- J1 q h0 l9 I$ }' S0 H}
2 C+ ^- Q4 I7 e: {3 n7 d6 d2 \) `1 ~9 n1 }2 \$ S
因为把大量的对象放到session缓存中会浪费大量的内容空间。6 b# _$ G4 ^3 j, D! b/ Y
" y5 ]8 K0 z3 V8 x2 L# D1 Z G7 C/ `# _2 L8 z
3 执行完session.flush()时,并不意味着数据就肯定持久化到数据库中的,因为事务控制着数据库,如果事务提交失败了,缓存中的数据还是照样会被回滚的。
9 O: w0 C0 s2 G" q
; Z5 F3 D# R* V, _; b! Y4 ]3 c" ]3 B) J- ~6 f0 Y; ]. T i/ r
|
|