TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
Session Clear()与 Flush() 解释
0 B! H) c8 N! M/ U- N1.Clear 方法
+ s6 v5 M( t. m# W3 s! [/ q; T7 ^ 无论是Load 还是 Get 都会首先查找缓存(一级缓存) 如果没有,才会去数据库查找,调用Clear() 方法,可以强制清除Session缓存。
- R: g7 U3 b' R: ?) A& u例:+ |) i5 ^. {# J5 f5 K* [
- public void testClear(){
1 S$ f& M. d7 U2 ?. C N2 A - Session session = hibernateUitl.getSessionFactory().getCurrentSession();: ?* d+ ~7 @9 S% P7 r6 _
- session.beginTransaction();
+ U; X8 x) r. d7 ?3 z - Teacher t = (Teacher) session.get(Teacher.class, 3);
3 x0 }9 t' {, a; L% `8 g' V" U& O2 q% a - System.out.println(t.getName());$ z5 u* g$ ]) p9 `' `" X; j
- Teacher t2 = (Teacher) session.get(Teacher.class, 3);" k, r7 w- r& d! {; G4 y: q5 `6 f
- System.out.println(t2.getName());1 ]- S+ Y$ q& T: ^$ A; Z
- session.getTransaction().commit();
0 H' L/ }7 F6 B8 ]# s' j - }
; h" h/ c% p; ~& A! |
复制代码 这里虽然用了2个get方法(get方法会立即执行sql语句),但因为第一次执行了会缓存一个ID为3的实体,所以虽然有2个get方法只执行一次SQL语句。
$ K) r6 Q' o' D; j. ?6 C- public void testClear(){* D; G+ K* h3 }& A; H0 H
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();9 E- H" t1 N3 K
- session.beginTransaction();
1 Y; o |5 P) B5 b8 Z - Teacher t = (Teacher) session.get(Teacher.class, 3);
0 E+ F. A- A6 K& T - System.out.println(t.getName());
. u. |/ o8 S) [' q9 s - session.clear();//这里不clear只会执行一次sql语句,有clear会执行2次
' V3 c. O. B- D' w - Teacher t2 = (Teacher) session.get(Teacher.class, 3);) Q& r7 h9 R# [3 j8 ?" V
- System.out.println(t2.getName());( Q1 Z) }7 c* E4 G0 \+ g
- session.getTransaction().commit();* l% x) J+ @4 f. L
- }
( U! X" y' S2 `/ c+ b' b
复制代码
# u' W* K Q6 v+ E: V! v& M, N& A/ I这里在第2次get前执行session.clear(),我们把hibernate show_sql 出来,它就会执行2次sql语句了。% `0 ?/ o$ c! ^: ?7 W# S3 G
所以session.clear()会清除缓存。
8 T" f: |3 |5 b. r4 v& B2.Flush方法
# `6 `) x L3 ?# c; H; x; L: X 可以强制进行从内存到数据库的同步。! x) J+ C3 g2 O' I1 b- u9 Y9 S' F
例:
9 N4 ^* ^! P) V% H# f- @Test) h( t- } Q) R$ y. k
- /**
) K/ l8 B6 W+ u! _7 a, u - * flush 强制与数据库同步
7 ]' i) l4 t1 g! w - */( { h) `/ r& A& t2 @& F7 }
- public void testFlush(){
/ B2 o- y7 [# H) I; P$ \ - Session session = HibernateUitl.getSessionFactory().getCurrentSession();. p: ^! M5 _0 |3 D, [
- session.beginTransaction();
3 ]7 a7 ?4 N0 L* V2 B1 v# D - Teacher t = (Teacher) session.get(Teacher.class, 3);
; Q% q) ]+ |; |3 p - t.setName("yyy");" ~4 X. A& f! r
- 9 s$ P# ~3 v& N, }$ D0 y
- t.setName("yyyyy");( x" ^; U6 s$ W/ y7 b
- session.getTransaction().commit();
* _5 F+ [( A( x E5 G" }- P - } B/ K8 j- d; r; g/ ~4 A$ i
- 3 K" T, ~( ?7 }7 O$ b" X# X6 l9 B- @9 ^
* a" {( X$ L# C" t$ ?; u
复制代码 看这段代码,我们setName() 2次, 但程序只会更改数据库一次,在commit时。
2 z# y5 A5 \9 D$ j$ a- @Test
; N0 J, P, T6 \+ @2 l. E- _1 k- T - /**
/ z) Y# ^* ?4 w4 O; X6 ` - * flush 强制与数据库同步) m! C4 @; x9 b" G7 v l
- */. m6 `1 ^5 [4 p0 S, V' x. x9 z
- public void testFlush(){* \+ T2 \8 F7 q$ G3 Y3 [6 n
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();
) y" G; S* p2 y5 E& u% A - session.beginTransaction();! j: _1 W# p$ W, T S1 y# Z9 }
- Teacher t = (Teacher) session.get(Teacher.class, 3);
+ h' l$ [1 _% J4 r: l - t.setName("yyy");! u8 V2 o/ A) e
- session.flush();//有flush会执行2次UPDAE,没有会只执行一次" @0 W3 O0 A# C: R N
- t.setName("yyyyy"); t0 ~. T4 |! @
- session.getTransaction().commit();
& K& N% p7 E- a - }2 h# z0 ? w& K7 J( M
' V9 Y P, a& M/ `& ?" ?% n# I2 V
% p1 C; v( Z. h# f7 o# B0 a# x
复制代码
1 x4 s# `" p6 r6 g- ]* h% D
; E5 j) z* s6 i# p. f我们在第2次setName()时 执行session.flush().
8 x) C9 i/ P% s: K/ O再看hibernate 执行的sql 语句# i% \/ ]& k' \7 L' \% H& [' e& k
- Hibernate: / R4 S4 A0 S6 r6 U L
- update
0 }! ~! }( u5 C3 l - Teacher 1 T, m7 v4 N0 v1 v+ E3 N
- set1 F' }5 }& n) l( o. b
- birthday=?,5 y3 _) W+ j# s% ~6 w
- name=?,
9 r+ P' _6 @; _% G4 m" F - title=? 1 B3 B% b+ Y- x& q( _: d! L* Q
- where% \. k) `/ y& O% L# Y
- id=?. i2 I0 `4 X2 v- I/ L
- Hibernate: / Z+ @" C6 d3 w+ U$ P' e
- update
& _& t0 H2 z. }7 G, l0 P+ I - Teacher , Y! V1 @+ u" M4 x$ f* _/ w
- set( u. a! `) @* b
- birthday=?,
5 t1 q/ q" Y. b0 n - name=?,
C0 h) X9 D! E( h - title=? 2 R" S! U1 h3 i) B# ?" l# K6 P
- where
. n' I2 U' r" d* A7 a2 B - id=?
" ]2 j3 ~4 V H# j1 X" T; ^( w
* O, ]6 E1 K$ ?' t3 E0 d
: x" c9 |9 r& y! c6 O5 G2 H- P
复制代码 + t v+ l5 j/ R7 ~+ g9 o: k; ?( N
3 P$ G( L7 z% L+ M/ p执行了2次Update, o2 Q, b: L, i
! Z. y5 O8 B2 ]7 q8 D* Y$ Q
所以看出来flush方法会强制与数据库同步。# J3 J& t- S2 d
( {6 E4 ~+ V z0 ~4 a3 R% I" R# }9 j+ L
Flush方法是可以设置的,也就是fulsh什么时候执行是可以设置的
: @7 p! r, l+ L, }3 z1 ^+ e; d$ I) B7 n/ d5 U
在session.beginTransaction前设置FlushMode/ E0 Q4 n: P/ u* \- H: S, r8 u
, D' B' k' _8 @" ?& C$ Ksession.setFlushMode(FlushMode.Always|AUTO|COMMIT|NEVER|MANUAL)$ Q/ [% r' U5 L" I: ?2 k, m
$ e8 f8 j/ }2 D1 G- kFlushMode有5个值可选+ O5 B+ j# C* d1 k6 g2 W
4 K& \0 z( v( W! |
Always:任何代码都会Flush" T: B2 O% ^9 X* H1 O" a
AUTO:默认方式–自动" o) g" K0 V) d+ E0 `1 t
Commit:COMMIT时
! K! d6 y) X. k% A& R; ZNever:始终不
/ B, _5 y4 T! Y" O2 M2 g4 \: l8 J EMANUAL:手动方式
; E- x8 C: k" I$ s' O
, _0 t& }, g7 l$ U0 |设置FlushMode 有个好处是可以节省开销,比如默认session只做查询时,就可以不让他与数据库同步了。
4 p/ i5 \9 Z9 j; u+ W================================================================" I2 z/ T0 D/ S
我说一下一些需要注意的信息:
7 P9 c4 r: |, s0 \9 W
4 g6 v- M Y! M2 ^' |- t# _1 session.clear()的作用是只清除session中的缓存数据,但不管缓存与数据库的同步。
, O7 l" S! a$ p* Y K8 X% l4 F2 t# i- y; e6 P, L
比如,你执行了
* M9 c* h/ L' z4 E. i
+ i1 q* z7 g6 R& s3 [' f- d! sPo po = new Po();
) s6 P7 a7 S0 osession.save(po),# n$ n7 x2 K; |; f, ~
* T) f' S" ]% U! o& p$ r- \
之后马上执行session.clear(),在事务结束的时候,这条数据是不会被持久化到数据库中的,因为一般缓存是在事务提交的时候进行清理的,当在清理缓存前就把缓存给清除了,自然就不会同步到数据库了。不过这个也有例外的情况,就是当对象使用native生成器来生成主键id时,当执行session.save()方法时,就会立马往数据库插入一条数据,这时候执行session.clear()也不会影响了。
0 s' I6 e- R1 R7 Z6 \6 Y( x a
* g& N \3 z) j% k- o, ~2 当更新或者保存大批量数据的时候,可以每固定数量的时候,进行清理缓存,同时清除缓存:
' S% Y$ N4 ]) r( m/ [- K& ?7 C% {$ P! f1 F' X+ j
for (int i = 0; i < 1000;i ++){
2 R7 V! d+ d8 j. M6 Q) v4 a2 i. ?6 S! E9 a D
if (i /20 == 0) {9 {( q# n3 Y$ o% z. M
4 I) G/ e# Q5 ]# o4 y5 {$ h
session.flush();* e7 N, Y8 ]- P9 s. @1 k
4 _/ Q# @2 g. f3 X# m b# B
session.clear();
% F" y4 g# b2 f9 h& m8 {" f. d}1 w$ B! U2 l+ x1 o0 v) s) a
}
|& @/ T5 F6 P. @3 _5 \1 p$ D+ J# Y% e1 ~
因为把大量的对象放到session缓存中会浪费大量的内容空间。$ c' X8 m8 K/ s7 e9 Z3 P) w
4 F1 O# b/ R) ^' ?7 q+ d; O
% Q3 O# a+ C1 ]
3 执行完session.flush()时,并不意味着数据就肯定持久化到数据库中的,因为事务控制着数据库,如果事务提交失败了,缓存中的数据还是照样会被回滚的。
+ H5 Z' n; f/ j& w/ n' f0 e2 y# W$ H: l- D0 P- S
$ L. e7 A1 d, A1 O7 ?. N$ | |
|