TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
Session Clear()与 Flush() 解释# H, C2 Y/ z, q/ \
1.Clear 方法
7 e P9 Z8 N# Y: j. N4 c 无论是Load 还是 Get 都会首先查找缓存(一级缓存) 如果没有,才会去数据库查找,调用Clear() 方法,可以强制清除Session缓存。! p* o. }; S7 }7 t- R- Z$ s o
例:' x7 r X) M# I K* m( `
- public void testClear(){
5 W1 w% [, @; b& J: a2 S8 q - Session session = hibernateUitl.getSessionFactory().getCurrentSession();
3 @( B( b; d! p - session.beginTransaction();+ p E' h/ m+ f$ y* j
- Teacher t = (Teacher) session.get(Teacher.class, 3);! U" p4 \% X: A {9 p2 S O* A
- System.out.println(t.getName());: c! {- A$ X* {5 L3 i0 ~
- Teacher t2 = (Teacher) session.get(Teacher.class, 3);3 r0 a' x5 e% ~0 P6 g
- System.out.println(t2.getName());
/ Q+ z7 D; ^ o1 S. Z3 L - session.getTransaction().commit();
- w i0 t6 i1 ?; l! |, u - }
' x& `5 W3 Q/ [2 @& [
复制代码 这里虽然用了2个get方法(get方法会立即执行sql语句),但因为第一次执行了会缓存一个ID为3的实体,所以虽然有2个get方法只执行一次SQL语句。
% I, x9 G5 b! l, w5 y& i g G- public void testClear(){
S" h a' [' v - Session session = HibernateUitl.getSessionFactory().getCurrentSession();: q X9 \6 s M" I& @
- session.beginTransaction();* S7 s5 @( j0 n$ D+ T) y7 K) g
- Teacher t = (Teacher) session.get(Teacher.class, 3); O M& v5 X: k% ^1 W) P( C
- System.out.println(t.getName());
4 y6 x$ }/ y9 _" z - session.clear();//这里不clear只会执行一次sql语句,有clear会执行2次
# A, I/ [) W* j5 _' |2 a( R9 X - Teacher t2 = (Teacher) session.get(Teacher.class, 3);* F& `8 v9 e, e$ o M! b, G
- System.out.println(t2.getName());; W% s& I7 R& i( X5 ?, R& f3 L
- session.getTransaction().commit();
' x( T2 e4 Y# Y+ v - }
8 f0 P- q8 G# X: N% C) I- S& h
复制代码
. v8 `, ^# i) C0 G# g这里在第2次get前执行session.clear(),我们把hibernate show_sql 出来,它就会执行2次sql语句了。* V9 P2 v; E. H5 q
所以session.clear()会清除缓存。
( H- Y' _# W- I; U2 K& |1 Q- N/ {2.Flush方法
* _1 ?3 V7 j3 `9 N( k 可以强制进行从内存到数据库的同步。" I5 X2 K% W/ B, } Q
例:
5 ?8 X0 e' L4 ~) V- @Test5 S6 x) y+ I& ^# F3 J# G) ]; a
- /**
* ^( \7 y3 V, b& g4 T2 t8 I - * flush 强制与数据库同步
1 U2 x: g0 d* [+ v - */
) u' z4 J0 i) i9 B1 x4 j2 t0 g \ - public void testFlush(){
' P: @4 ~6 k0 C) M1 J - Session session = HibernateUitl.getSessionFactory().getCurrentSession();; G3 @; F4 H) _+ V% {
- session.beginTransaction();
% L& ~+ Q, M, X' A3 e: k! h - Teacher t = (Teacher) session.get(Teacher.class, 3);7 X8 U+ K. Z6 a- G1 N. [/ u3 g- s
- t.setName("yyy");
$ V2 x2 C9 g: R" y! v7 [. R/ d - + s# W9 m" L; H
- t.setName("yyyyy");
( \5 q+ Q- E- B - session.getTransaction().commit();) Z2 m, E9 b% h. W, `* A
- }
2 b6 h2 |) C3 C( ]. _8 Y( ] - # o, v9 d; @! p0 y- e
- 5 a1 T" ^+ }" \, @) {8 h
复制代码 看这段代码,我们setName() 2次, 但程序只会更改数据库一次,在commit时。( b# ~: v- J% K. x( E1 x
- @Test8 i, ?9 y b5 q/ C( [! N
- /**: B" G+ a" @7 T( r/ K% `
- * flush 强制与数据库同步. b6 E$ c& i, ]4 Y' c0 R
- */
) e2 t; ~5 t' B/ R: c( x - public void testFlush(){
7 }, p" G7 G( w& J- `- n - Session session = HibernateUitl.getSessionFactory().getCurrentSession();
& m+ d9 m1 |2 Q ~: { - session.beginTransaction();5 D6 K/ e) v) X2 v
- Teacher t = (Teacher) session.get(Teacher.class, 3);
2 M4 o1 j$ R, Y3 c# x8 l - t.setName("yyy");
1 J( x4 ~% W) P, S& g* F x! O - session.flush();//有flush会执行2次UPDAE,没有会只执行一次
5 v' @/ |7 |3 e2 l) C8 C2 G - t.setName("yyyyy");
% }0 Y" u; G9 J& d8 d. _ - session.getTransaction().commit();
9 b& D: W) }2 J: A! O) f& R2 M - }
8 D! t. C, V; V( L7 o& {3 a% h
# e$ M3 q) h I" z- " Z# O$ E9 O0 ]/ k
复制代码
) Z* F/ a5 s) j; v6 v
- T2 K/ x1 Z$ j5 T% @ Y我们在第2次setName()时 执行session.flush().
3 @3 P2 H* x% @3 Q再看hibernate 执行的sql 语句
# B9 o) L% e3 [- ?, s( ^# D- Hibernate:
: E6 t' }& G0 N4 s3 Y - update+ i$ U% P8 Z1 w: [* A6 m4 q
- Teacher 7 G9 ^' k1 X3 O) ?* V
- set
! E- b5 O; V" Q4 ~ - birthday=?,( Y& L4 g7 t1 R+ I) j. J* ?, J2 d8 V
- name=?,
6 [" c9 x; ^# E) g! O( v* ^ - title=?
5 ^/ P2 b" d3 y5 V, b1 U6 @2 D - where9 R6 J2 T3 o& Q; n+ ~, ]
- id=?8 w* t* @% U+ T- D+ G- I
- Hibernate:
8 P7 P- J5 R2 w! O1 t, L - update. o" p* w: s: I% B* j+ \. p3 E
- Teacher
& |" U" A* C8 h - set4 M5 r- @2 Q0 B2 D4 u S% X
- birthday=?,
- H6 n _. b: W3 e) a - name=?,
; Q0 z2 S7 w3 z" J: q7 E - title=? 1 u U; C5 V/ V
- where
1 X* K$ e. I5 C6 n) h* K! |/ G h - id=?
+ Z3 w2 ~/ j8 _ ]: L5 B2 D% Q - # ?# u1 u0 z8 @3 F! Q" w
- ; [' m! k! [% _4 x0 Q
复制代码
! l; H* e) t) }; u+ r9 w$ [* @4 M$ t* L' X: X/ `( X
执行了2次Update' B# Q( _4 p& f5 n; X
5 S/ `8 k% [1 i2 G" P所以看出来flush方法会强制与数据库同步。( Z0 O# d" R! s* k
$ ~; F1 U3 `. z/ |' m
$ c6 A h( n5 C* _9 `
Flush方法是可以设置的,也就是fulsh什么时候执行是可以设置的
7 B! G ~6 ?6 L, `0 A. x) j. Q! T
* B# M$ x2 l2 Q/ P* f 在session.beginTransaction前设置FlushMode
$ P' l6 |- Z% N
3 l! [* _2 F7 I( U0 D3 N& Nsession.setFlushMode(FlushMode.Always|AUTO|COMMIT|NEVER|MANUAL)9 B" b* |! r' X- K$ m$ L
* V1 K1 ?% V7 _. e8 I& HFlushMode有5个值可选( B+ v7 ?4 W X9 a$ }, X7 M2 t
; [, f, h3 r' c: d# O0 O' j2 R
Always:任何代码都会Flush
; b3 [# h5 I; _$ vAUTO:默认方式–自动
' r+ |2 k% s; \0 S8 k" e( [9 aCommit:COMMIT时/ C' n; B3 z' J7 C
Never:始终不 f4 }7 I& ~9 `: N, q4 r
MANUAL:手动方式
$ Z$ o$ J y2 K1 h+ B) J5 \4 ^, \; t1 _8 i
设置FlushMode 有个好处是可以节省开销,比如默认session只做查询时,就可以不让他与数据库同步了。
2 x. v1 @2 y. [8 W, C4 \2 F, v================================================================
9 Y7 c, I5 ~: \我说一下一些需要注意的信息:
+ @' _* M+ E" O/ w2 M w0 X$ M0 y; F
1 session.clear()的作用是只清除session中的缓存数据,但不管缓存与数据库的同步。
8 G; n3 o6 r, d
( P0 {( ^" N. e7 m9 E4 O0 [9 Z比如,你执行了
9 C! l7 n6 h( I" I9 m4 l7 W Z6 O" \8 N$ q
Po po = new Po();
7 L" y1 O( ~1 q& l1 usession.save(po),
3 |8 C7 k _4 w! S# q6 V4 q! V/ k% f6 M+ H
之后马上执行session.clear(),在事务结束的时候,这条数据是不会被持久化到数据库中的,因为一般缓存是在事务提交的时候进行清理的,当在清理缓存前就把缓存给清除了,自然就不会同步到数据库了。不过这个也有例外的情况,就是当对象使用native生成器来生成主键id时,当执行session.save()方法时,就会立马往数据库插入一条数据,这时候执行session.clear()也不会影响了。
; U% w8 c, T: M! G/ Y" `* W) G d0 f9 A8 F4 s. E
2 当更新或者保存大批量数据的时候,可以每固定数量的时候,进行清理缓存,同时清除缓存:+ Y4 i: [0 F8 n, _1 o' z
" @# l$ P5 R; Q" W0 K; v) zfor (int i = 0; i < 1000;i ++){' G: k! a$ Z$ o
0 j$ d1 }5 H" b; l# K
if (i /20 == 0) {7 d4 C2 O% s0 J$ Z2 k
- u0 a: d0 e. @5 P7 {0 o
session.flush();
8 w* ?' h3 O% f, h, w2 h1 a: y; {; w# h& ], J9 k' A
session.clear();/ [6 g# X& _9 V6 y
}
- L6 P1 r, A6 |4 y; @) n}
; k, b7 q# _+ [. G7 Z" d
8 F4 \$ A+ @! y0 M4 _7 \- b因为把大量的对象放到session缓存中会浪费大量的内容空间。; C2 z' b) z( W9 T+ {# g
+ ^4 w: n& G; M' W
' N: X8 S( l7 B7 a( ]9 ]" w3 执行完session.flush()时,并不意味着数据就肯定持久化到数据库中的,因为事务控制着数据库,如果事务提交失败了,缓存中的数据还是照样会被回滚的。
0 y* Y( R; I! Q- K% y0 {
: {( y0 D. b5 @2 t" ]9 z% C Z% M& K2 s1 u* ]5 y1 I3 ~
|
|