TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
Session Clear()与 Flush() 解释6 z0 ]3 G4 q: j! N4 I
1.Clear 方法$ h) Q% _4 a/ T: S( ~
无论是Load 还是 Get 都会首先查找缓存(一级缓存) 如果没有,才会去数据库查找,调用Clear() 方法,可以强制清除Session缓存。2 e! u6 A% y5 n) _
例:4 t1 I% ?1 }% B
- public void testClear(){6 R2 |" d; z5 p" W2 \& _
- Session session = hibernateUitl.getSessionFactory().getCurrentSession();
+ ?, B3 v0 k/ I - session.beginTransaction();0 L' ~. p8 y5 k- m- o* I
- Teacher t = (Teacher) session.get(Teacher.class, 3);
+ \) w- [: Y1 Y% p5 r - System.out.println(t.getName());
! o4 |8 R' }3 z7 F4 w - Teacher t2 = (Teacher) session.get(Teacher.class, 3);
/ n" f: r0 \$ o8 E" b - System.out.println(t2.getName());
2 \5 h& C. H3 @+ N, K* [8 D+ O - session.getTransaction().commit();
9 G( K' f1 x& E1 |, e - }& L: T7 f6 h% l
复制代码 这里虽然用了2个get方法(get方法会立即执行sql语句),但因为第一次执行了会缓存一个ID为3的实体,所以虽然有2个get方法只执行一次SQL语句。$ B( L6 D' w# C c5 w0 k
- public void testClear(){: m, i9 r$ H6 W# D( l
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();
* b# g* D7 Z3 [4 X& O - session.beginTransaction();
$ {: h' g# _8 W) W, V6 ^- O - Teacher t = (Teacher) session.get(Teacher.class, 3);
4 V {, Q4 V* ~2 R' A e - System.out.println(t.getName());
0 i# s5 [: v& |' r7 O9 y" [& q - session.clear();//这里不clear只会执行一次sql语句,有clear会执行2次8 c+ ^' e i5 ?) l. n
- Teacher t2 = (Teacher) session.get(Teacher.class, 3);* F8 R; W" _% c( F E# B4 A& R9 b
- System.out.println(t2.getName());
5 K8 p {' `7 @ m' E - session.getTransaction().commit();, T5 G9 ]& p* o7 }; {
- }3 ? W2 p- u9 }( y# x1 V, F$ L
复制代码 " Y: E" P& J% ?8 T% ?% J
这里在第2次get前执行session.clear(),我们把hibernate show_sql 出来,它就会执行2次sql语句了。: z' [) U. B/ B6 T! [+ |% g
所以session.clear()会清除缓存。( @* X# }( C! }0 O
2.Flush方法- Q/ l' h( T; |2 Z* S
可以强制进行从内存到数据库的同步。
2 y1 i; M$ C& f- [4 b. B! N例:5 Y# @7 s. ]( K! |
- @Test t2 j7 v. `" Z( {: D) k
- /**
: A; h5 c9 ]) ]( s$ C# @% w+ n: v - * flush 强制与数据库同步
; r- t: ]: \7 K4 {& E3 B) y& t - */ ?4 x, V+ k2 n/ l
- public void testFlush(){
. k% u' i6 D/ ~+ c% y7 S2 M% u - Session session = HibernateUitl.getSessionFactory().getCurrentSession(); w! y1 n8 o( y+ x7 m
- session.beginTransaction();6 S' R7 }) M5 _$ v+ v- \; k6 }
- Teacher t = (Teacher) session.get(Teacher.class, 3);
# G0 Z4 o, \7 ^$ t* ~ - t.setName("yyy");9 X Z7 q6 a, s N) Z+ ~
-
) i1 {4 z { `' T) d - t.setName("yyyyy");" a' @, |: s2 l7 Z8 t! y6 H
- session.getTransaction().commit();/ Z; f% E; `. f8 T. t
- } I- f; ?5 R* D) I6 y
- - [7 m9 a* b( z/ @
# \4 K7 B- v6 @
复制代码 看这段代码,我们setName() 2次, 但程序只会更改数据库一次,在commit时。1 J \) B% n( p1 _( I3 y# a
- @Test
& ~; M7 P: }( }; Z" B! ?& x - /**
' h8 Z" }' n" \- {% _ - * flush 强制与数据库同步
4 ?) c+ }$ V& v: W, |6 j - */
9 |3 j/ u( Q% U* m& d - public void testFlush(){" W2 S. b5 \1 u2 s$ k9 E
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();
& D' h1 a) g) z- m6 C* [ - session.beginTransaction();
8 _% t: @1 J! \: Q - Teacher t = (Teacher) session.get(Teacher.class, 3);
4 h" v% G6 |" G, u1 I, O - t.setName("yyy");
% \* R( m0 w( J4 `# d( {8 I" p - session.flush();//有flush会执行2次UPDAE,没有会只执行一次
g) g# u- V+ }# N* B) Z% Y - t.setName("yyyyy");% Y% k6 t6 d; `' e! N; E5 s
- session.getTransaction().commit();, e8 f% y! S4 [* h
- }
# m. C6 g# f8 Q - ! v* K/ K4 O! f: Z+ {
- ; P# K$ }, k" x6 V6 G6 L
复制代码 1 R5 ?7 @/ M7 M o$ w
@. E' X- f# p8 d9 S" j* c我们在第2次setName()时 执行session.flush().- f+ _1 _$ B9 Y: ~, h! r1 r2 a
再看hibernate 执行的sql 语句- D1 p" _+ ^/ e! N; q, c# E" b
- Hibernate: 6 C% B6 T& W( G F' r* O+ t- A* O: ]& K! D
- update# c5 K7 q) d' k5 [: Y
- Teacher
/ u3 u& r k h! e! } - set& _( e( S% y7 C: i: L4 B* C
- birthday=?,, ?; X+ b+ l! N
- name=?,
( b, o, X3 Q8 H - title=? * o5 L8 `/ e, @, O& k+ ]( [/ b4 i2 L- x
- where
9 R9 Y$ ~ Q# P - id=?( J/ C. X! ]3 R, ?
- Hibernate: / }9 `7 h% S. i- s* p' u
- update& q+ h0 s. q2 v' E. t. H R* c
- Teacher 4 J8 Z4 |9 w( p4 Z
- set) y6 }' A3 X% v. n. ?: w# Q' f5 P, t
- birthday=?,
5 l. D) H ^/ Y" Q - name=?,; } d2 _$ f5 |$ e
- title=?
! Q+ l4 ~; q7 m' g l - where
2 m8 O9 `0 N+ { - id=?- A9 Q/ L' Y4 o8 l- d7 Z$ e* o0 Z& r
r8 I6 ^9 T7 T
$ r' P4 y( h( B# D3 m: d5 [. {4 i- f
复制代码 9 t: b# B; X5 F; I6 r8 U
y3 A$ g( N% c: {+ J: q" `执行了2次Update
. K, j( J O4 ]$ x/ Z1 Z% s
7 i: _2 Z" N) d3 X4 I所以看出来flush方法会强制与数据库同步。+ H, b" ~: \) V8 F
3 K7 X* Q$ f- a; X
& u3 ~8 d# x! H% L- FFlush方法是可以设置的,也就是fulsh什么时候执行是可以设置的) n( N% Y# [; T& |; y* m% x
5 F. K' q3 X6 ]4 d0 D
在session.beginTransaction前设置FlushMode2 [1 c" j' b" ~7 v3 U4 [, N' m' s
2 [0 M' V; o9 v9 s8 jsession.setFlushMode(FlushMode.Always|AUTO|COMMIT|NEVER|MANUAL)5 v) R6 j: \% q( _1 V( J
' n3 H1 s( w( @FlushMode有5个值可选
8 G4 \" m, a! W1 S6 M! D c
0 X* L: T% g5 ]$ N) E G6 h! g+ Y2 uAlways:任何代码都会Flush
{! ^5 | G: ^) b1 C- D5 u% u7 b, lAUTO:默认方式–自动3 p' ^* \* ?$ [; H7 z! o- s4 L( y8 T
Commit:COMMIT时
# ` W$ U- G- s/ j6 b, YNever:始终不; v; J8 t3 C, M$ k# f, O
MANUAL:手动方式$ g9 w: | }0 h+ H) O# j
1 e t) X4 G; ~7 F
设置FlushMode 有个好处是可以节省开销,比如默认session只做查询时,就可以不让他与数据库同步了。
9 C) t* H0 ?; b! O9 |6 N) ?& v================================================================
; u# s. D# \+ D }& f' ~我说一下一些需要注意的信息:+ t f' w- V6 W
6 a) A( ~0 t4 F1 session.clear()的作用是只清除session中的缓存数据,但不管缓存与数据库的同步。2 }& d( I+ C ^# |( z( k/ H/ I/ Q
( [1 m) O9 v& d7 j7 Z
比如,你执行了9 N* u3 f* D, G7 Z% }( {4 o8 N
! E# Y z( d3 {5 K- {& |Po po = new Po();$ M) h& Q8 E3 |* v: B6 z2 u
session.save(po),; M3 J: v) F% e# Z9 e# }8 A" J, E
0 N W6 y+ Y/ E7 K% ~+ j' K之后马上执行session.clear(),在事务结束的时候,这条数据是不会被持久化到数据库中的,因为一般缓存是在事务提交的时候进行清理的,当在清理缓存前就把缓存给清除了,自然就不会同步到数据库了。不过这个也有例外的情况,就是当对象使用native生成器来生成主键id时,当执行session.save()方法时,就会立马往数据库插入一条数据,这时候执行session.clear()也不会影响了。) U3 ^+ E4 m) {6 ]0 w9 ~
3 l# m( P3 P" N. P
2 当更新或者保存大批量数据的时候,可以每固定数量的时候,进行清理缓存,同时清除缓存:6 }$ a, X8 `. A
x7 y5 ~1 @1 }$ ]
for (int i = 0; i < 1000;i ++){: ]% B, T5 q5 }+ p
& S& I( a/ Y4 W! m& q0 Eif (i /20 == 0) {* y8 w- D( h* O* P p
: W& I! x, k: y- q, |3 J7 e
session.flush();
' B q4 }0 l9 w& k! V3 O j9 u- c( d1 |8 K; |
session.clear();
$ W& S7 X7 q% Q2 f. g! ~}
# P5 F$ N" c' ^1 ^- R}
4 J0 `' P* }9 p4 ~! q! k
, K' b2 T5 Z: M7 U因为把大量的对象放到session缓存中会浪费大量的内容空间。2 `8 ^: Z' `- {" T
) i6 c4 z) \' j- @ l4 `6 x( p; D% Z& M% p' y
3 执行完session.flush()时,并不意味着数据就肯定持久化到数据库中的,因为事务控制着数据库,如果事务提交失败了,缓存中的数据还是照样会被回滚的。
: G/ |8 f ?* o( t/ p& B0 s. ~" N" K$ i& G, G! b$ e
! ^" o6 w$ P5 o, T2 b |
|