TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
Session Clear()与 Flush() 解释
. r- ^3 G' f! ?: W+ h1.Clear 方法
0 _' {7 L5 D8 b9 d) {% r3 J1 F) s3 m 无论是Load 还是 Get 都会首先查找缓存(一级缓存) 如果没有,才会去数据库查找,调用Clear() 方法,可以强制清除Session缓存。7 t6 n4 s( S) Z' m4 ]. F b
例:/ a( P- V' u. t: h/ W2 \
- public void testClear(){
5 m! R. Z0 ]# P/ u6 ^ - Session session = hibernateUitl.getSessionFactory().getCurrentSession();9 q; `7 G' l5 ~
- session.beginTransaction();' Q2 t( R% z6 I% k3 \0 p6 k/ x5 Z
- Teacher t = (Teacher) session.get(Teacher.class, 3);
9 R7 s1 F4 T5 l4 M - System.out.println(t.getName());
4 I( \4 e E! a' [( A - Teacher t2 = (Teacher) session.get(Teacher.class, 3);0 G# ^! h' E8 u [. s% j
- System.out.println(t2.getName());
" a" y8 D* ~* y0 C1 ?+ v - session.getTransaction().commit();
/ D# A7 j$ \! l6 L4 { - } ]5 D0 {& d# u* J+ B$ G
复制代码 这里虽然用了2个get方法(get方法会立即执行sql语句),但因为第一次执行了会缓存一个ID为3的实体,所以虽然有2个get方法只执行一次SQL语句。
- U/ Q) o' j# V$ M& R% M- public void testClear(){8 \# T8 @% D' k1 j
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();
/ t: M: D. _; p# k8 K) G2 k - session.beginTransaction();3 [: U" Y$ |$ t/ F, A5 w
- Teacher t = (Teacher) session.get(Teacher.class, 3);
D2 `+ t! Z0 q6 R4 { - System.out.println(t.getName());
3 c% s! P- N) f+ b - session.clear();//这里不clear只会执行一次sql语句,有clear会执行2次8 W- U0 Q8 t9 h5 v$ S0 V
- Teacher t2 = (Teacher) session.get(Teacher.class, 3);
4 [4 _' Y! d" Y2 t8 N- [ - System.out.println(t2.getName());
; |# [3 i* Q& m; Y: ]' R4 K, C - session.getTransaction().commit();/ u6 g; v* |8 Y9 p* Q
- }. r% U6 B; C j; c# y* U
复制代码 , o4 z6 ?- d$ |
这里在第2次get前执行session.clear(),我们把hibernate show_sql 出来,它就会执行2次sql语句了。
& w8 \ a8 I4 E" o" i( _7 y$ ?所以session.clear()会清除缓存。 D- ?/ m2 ~& x7 c
2.Flush方法- x: N' O1 w8 q& X9 r* c
可以强制进行从内存到数据库的同步。. r) G8 j( @+ ]% p" ]! d
例:
4 g' l6 J* v$ V- @Test* J) y _* t* a+ V
- /**
7 I) x) A' \& }; R/ ~$ S - * flush 强制与数据库同步, e; Z) }5 f; _ W) r& `
- */ O( _: l8 W& L( n- b
- public void testFlush(){
$ ]: a' M; d- D! r& m: G9 I - Session session = HibernateUitl.getSessionFactory().getCurrentSession();
& K' C0 u) Z+ D @ - session.beginTransaction();# J, T2 P) L( {8 e% \
- Teacher t = (Teacher) session.get(Teacher.class, 3);: S, ^3 r: r% {! \# \
- t.setName("yyy");
1 Q2 o0 \( K8 o! I5 Y1 t - # a- c0 E: }% L# j( d D3 G5 a
- t.setName("yyyyy");
* x- b* s% Z) `' p1 l - session.getTransaction().commit();% b& |. s0 m: h& e& j# w. O# S
- }" T! N! i) k6 G) H2 }+ C
- 9 L* Z: g( ?# m. l1 N" g' K
- . A. f, M7 Y+ L$ V
复制代码 看这段代码,我们setName() 2次, 但程序只会更改数据库一次,在commit时。
! S$ @5 ^9 O8 q" x& B3 d- @Test- ~% r, H% T' F* M
- /**
- U+ R8 k% F' `$ b - * flush 强制与数据库同步8 i6 k2 T/ v" J" r
- */
D/ i! z+ a+ S9 ?) U0 p) ^ - public void testFlush(){
# B2 K3 Q& C" Y* s+ O) ] - Session session = HibernateUitl.getSessionFactory().getCurrentSession();
+ j/ u+ E7 z: t$ L - session.beginTransaction();! f: u; R% D7 c7 Z
- Teacher t = (Teacher) session.get(Teacher.class, 3);1 B j4 O; [3 b. R( c" B% j- K
- t.setName("yyy");
- a! V. B: t0 D; a# s - session.flush();//有flush会执行2次UPDAE,没有会只执行一次) t3 X& s" a1 j* h; D1 m
- t.setName("yyyyy");- j+ I% J! }* E1 ~! v. {
- session.getTransaction().commit();
3 J9 O! w O3 ]. u2 m - }
$ R9 F" n& d9 d; o$ }5 t; M4 l% Z* {
/ K. y) m. B( v3 z7 K. ?1 \3 }: t9 p- 4 K; Q+ s' a$ {5 ~5 J& r/ C
复制代码 " V1 k' ?6 _0 W. @# y
) Y/ B/ s7 O9 z, w+ B0 y( D+ ^/ R! u( F我们在第2次setName()时 执行session.flush().
" b; e! Q( g m& W7 S5 }" b$ {6 U) o0 s再看hibernate 执行的sql 语句
) {+ G9 k1 M0 _7 i9 A- Hibernate: ! p1 H' ~# c7 V2 C, [9 ]2 O
- update
0 Z: F1 {9 n$ o. k) o2 U% a9 ? - Teacher ! x( R' {" w) s7 |5 N
- set
# |8 z* c. |2 l1 x& i i - birthday=?,
2 X. C! U7 N9 ^& O" Z - name=?,& r2 Z: R$ x) W1 b2 f5 M+ v
- title=? - E) c+ {4 e2 ]4 k
- where) p& x* s! Z$ H3 h9 a5 q
- id=?
7 z- r: G$ U ]$ h$ i( { - Hibernate:
( Z) R- s2 H8 |3 C - update
$ e. a6 k! ?; S3 ] - Teacher
' e/ V+ g4 z, [. M - set- A6 t$ K5 Y$ B: c
- birthday=?,1 U3 X, c F8 l4 I! k8 Z5 E; K4 _
- name=?,$ s1 o; L$ o | O$ J. F
- title=? 0 [& z! a2 e7 T5 @2 D; u
- where
, ?; I/ J" I( Y3 s" s - id=?( m3 ^* e. s9 _" E8 W& k3 j
: u3 j- @6 Y g7 h9 E- 6 p7 }* B" K; [6 h7 q5 @- N
复制代码 ' e; p0 V9 \& _0 o
+ H3 |, r% H# l, U+ t0 m
执行了2次Update
. A) I$ B" i! m' b% G+ y7 C; K/ {/ r6 a4 t/ _/ i9 W- D2 r1 n
所以看出来flush方法会强制与数据库同步。
- y6 b- n% p) d' ^4 R0 c& h U1 L* k& i8 A# d" i
! N: Y# |6 |6 d0 {9 q0 {( u3 M0 ?Flush方法是可以设置的,也就是fulsh什么时候执行是可以设置的$ v* ]$ @) z+ U: i: _4 P( `9 { W
" {/ p3 b3 ?' g0 _/ F 在session.beginTransaction前设置FlushMode
1 h' t& D4 p2 A1 x( ]/ W
+ C; s" y! \1 c2 K/ J- K- Psession.setFlushMode(FlushMode.Always|AUTO|COMMIT|NEVER|MANUAL): W4 C0 N3 g( ^: b7 G2 c
j9 c' n' v' ~& H q# G, c
FlushMode有5个值可选/ k: o9 B( I1 v# F. l0 V- `
) K- Q% L1 S9 M/ j zAlways:任何代码都会Flush* x; b0 n$ X3 B) W% m
AUTO:默认方式–自动 x* p* T C1 D$ Z; F: A; D
Commit:COMMIT时, ~+ w7 k8 P {( O$ G+ K4 H
Never:始终不
0 h" C; l1 N9 ?: K" z! HMANUAL:手动方式
6 {9 o: K# B, [; S5 G
" S0 G7 N6 V: J5 o设置FlushMode 有个好处是可以节省开销,比如默认session只做查询时,就可以不让他与数据库同步了。) X% y. s& K7 z6 ^4 J l
================================================================8 V* K# F7 n' j
我说一下一些需要注意的信息:( u5 \0 b: F; R# a6 w- ^
' S8 ^) p8 u5 _1 j' A1 session.clear()的作用是只清除session中的缓存数据,但不管缓存与数据库的同步。9 U" j; z, F' ]
4 b( T' S6 i$ e# f9 l. @) C: D7 _
比如,你执行了
8 o# d) Y: P, z8 N& p+ ~" o9 d6 m9 e$ S) o) k5 S! S4 C& F1 P
Po po = new Po();
. z; h# J* ?; T; dsession.save(po),
9 _! J( B: |- e# \+ K3 K) I6 ?
( K9 [0 o8 L; q+ y% n% y! k2 S6 Z之后马上执行session.clear(),在事务结束的时候,这条数据是不会被持久化到数据库中的,因为一般缓存是在事务提交的时候进行清理的,当在清理缓存前就把缓存给清除了,自然就不会同步到数据库了。不过这个也有例外的情况,就是当对象使用native生成器来生成主键id时,当执行session.save()方法时,就会立马往数据库插入一条数据,这时候执行session.clear()也不会影响了。
6 M: d* y$ O. D* j/ e1 E# ?3 w. L2 g) |, N2 W3 h
2 当更新或者保存大批量数据的时候,可以每固定数量的时候,进行清理缓存,同时清除缓存:
, f" r' V& l8 K- r! p" m8 A& k; Q. H
for (int i = 0; i < 1000;i ++){
( W- k( p; y5 h* }: l: w8 V6 c
* `2 [) Y, _# Eif (i /20 == 0) {* k' q4 g2 f) E4 s5 j, U. E$ l
8 U0 K1 \ o0 g; {
session.flush();3 J8 H4 E7 z, \$ S
8 v# D+ {7 j7 L7 G+ N" L
session.clear();0 Y6 d4 {7 M/ F8 P; j# T
} g. L3 ^. {0 _- |; X! n& X- R
}
* g/ p- y- j; x. e, @) `
' j; e( \- G8 K7 I6 G9 X7 ?因为把大量的对象放到session缓存中会浪费大量的内容空间。
7 ?1 }8 B7 y% n* O L' p# w* D- H" g
" W, S1 M d6 }3 E, |$ ~' \, l3 w, ^+ A: b! q* C. B
3 执行完session.flush()时,并不意味着数据就肯定持久化到数据库中的,因为事务控制着数据库,如果事务提交失败了,缓存中的数据还是照样会被回滚的。
. }( S' y& {4 ]3 e/ W0 g. @
! j; I: Y+ s% R5 j! H* `1 E- c: K+ R7 R2 v9 n
|
|