TA的每日心情 | 衰 2021-2-2 11:21 |
---|
签到天数: 36 天 [LV.5]常住居民I
|
Session Clear()与 Flush() 解释
0 B& y7 D0 U9 e( ]3 S! n2 D1.Clear 方法" _) C$ \6 B' o& u+ N
无论是Load 还是 Get 都会首先查找缓存(一级缓存) 如果没有,才会去数据库查找,调用Clear() 方法,可以强制清除Session缓存。0 h$ Q4 @/ n- e7 d
例:- D6 k+ {6 F" j \
- public void testClear(){
7 s' |* [: [; W4 _( B& u- q d% B - Session session = hibernateUitl.getSessionFactory().getCurrentSession();
0 g/ q8 i# f, g$ H$ w2 E - session.beginTransaction();
. O4 Z, Z9 i$ p5 ^2 ` - Teacher t = (Teacher) session.get(Teacher.class, 3);
5 K, {7 k/ x0 e$ [% u/ @ - System.out.println(t.getName());# z6 B4 V' b. J" F4 u: `
- Teacher t2 = (Teacher) session.get(Teacher.class, 3);
1 O: k/ ?$ b8 t5 c B6 {% Y, } - System.out.println(t2.getName());
, c+ b5 Y% v* E* b- h - session.getTransaction().commit();8 g' ~# I [& r) e w" x
- }
, ~ b% W, U, ]
复制代码 这里虽然用了2个get方法(get方法会立即执行sql语句),但因为第一次执行了会缓存一个ID为3的实体,所以虽然有2个get方法只执行一次SQL语句。
' @0 a+ m$ G; D- public void testClear(){3 L8 E, \" t) a, x
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();, `9 r4 G+ M* J- V8 X N% H
- session.beginTransaction();
; F# E/ W ^: M! H* j - Teacher t = (Teacher) session.get(Teacher.class, 3);
1 W6 h9 e+ U7 n - System.out.println(t.getName());
% I( {' V7 X+ D" z. G; m7 U3 h - session.clear();//这里不clear只会执行一次sql语句,有clear会执行2次( n ^3 y8 {) d: T! U2 [) M
- Teacher t2 = (Teacher) session.get(Teacher.class, 3);2 t/ R: V- ]+ ~7 }
- System.out.println(t2.getName());
( v& b+ y/ v5 D! S' K+ T1 n4 D3 l - session.getTransaction().commit();
* V5 z6 O: x! @/ I6 O - }
( Z. j& W9 ^: ]. G4 P
复制代码
! E6 ?/ T3 q2 b M7 w* \3 y3 m这里在第2次get前执行session.clear(),我们把hibernate show_sql 出来,它就会执行2次sql语句了。
0 @: ^9 M: w$ i4 q9 G所以session.clear()会清除缓存。/ ~+ S: @" c, ]5 r5 I
2.Flush方法
. l* C7 S' q! Z" j r 可以强制进行从内存到数据库的同步。! l" L8 l9 g S3 |2 y& ?
例:
7 k+ h9 |; E$ t! E- @Test }/ g4 `/ M$ B5 v$ v3 {
- /**0 n- }. V# C& \/ C' P$ J ]
- * flush 强制与数据库同步" I6 ?, w+ B% L; y, M6 M: _/ E+ b
- */. h1 m7 ~3 Z$ n% s
- public void testFlush(){. Q. f4 h3 x0 q
- Session session = HibernateUitl.getSessionFactory().getCurrentSession();! i6 D) g2 e6 f+ C
- session.beginTransaction();9 h, ` K$ R$ k: w2 Y) @1 J
- Teacher t = (Teacher) session.get(Teacher.class, 3);
2 e: M; v1 ^+ M. ~8 Y. y1 O - t.setName("yyy");
" @; P; E! ^) b+ U& ]+ ^5 P) l -
4 r- ?+ e5 f5 c" O8 o% f7 m - t.setName("yyyyy");
1 G" x7 m: o3 |' d& q4 V- Y - session.getTransaction().commit();
+ B2 q3 o6 \) c" c - }3 ~- S+ v6 y% g- z6 O
, i0 v; B7 S# k% Z. P. V% t5 N- $ z. V* l J* {' _- H, I, g# W7 H
复制代码 看这段代码,我们setName() 2次, 但程序只会更改数据库一次,在commit时。' F) t1 V- F, `4 O( \
- @Test
1 H' C# v3 k& A* q/ h1 o' u& L - /**
" h; a) w! B. k) O( `3 _ - * flush 强制与数据库同步7 X. y& [4 H4 ]% G7 J
- */
- C$ I' j; P9 e$ _0 v6 _0 x4 N - public void testFlush(){
7 y3 I, |5 L# D, z - Session session = HibernateUitl.getSessionFactory().getCurrentSession();
0 Q; _) m) B, l n. H - session.beginTransaction();- _5 f$ P ^* Q# n3 w2 Q
- Teacher t = (Teacher) session.get(Teacher.class, 3);& i( Q7 X6 r" k- x/ w' b
- t.setName("yyy");6 @* Z$ ]6 ~7 Z/ \7 ?
- session.flush();//有flush会执行2次UPDAE,没有会只执行一次' \, B' q" k3 K: Y9 N U) T
- t.setName("yyyyy");9 g5 i! ], ~* V2 D7 ?
- session.getTransaction().commit();
; k% p0 j& j7 A9 u - }
" p9 k1 x4 a6 A4 K6 q+ y - $ @. y. g% M1 j0 a
- , K! h' N7 J) L, }& h
复制代码 5 w! ~5 }9 O0 t( z$ {5 C, C. K; B
+ a' ~- D7 h- X1 G7 j' K: m- v我们在第2次setName()时 执行session.flush().! a' Z( V% p. X5 H, J
再看hibernate 执行的sql 语句
' |8 [& o. M5 b# `- Hibernate:
7 M. r ?" y; I/ z* E2 l - update
: N j6 D* e+ M: T$ ~) @3 h; ~ - Teacher
9 ?; m6 Z J$ @/ g, ]; B* }9 v! m - set6 I- ]( r; ~3 f4 U, C
- birthday=?,
0 |2 o' D- y7 v) n* L9 q* S - name=?,) Q6 e# n( J: K6 |: A
- title=? ' E( H+ K/ A7 T0 I" ^1 i% R
- where
% |* V$ e" D% N9 X - id=?
7 H# I9 x! e1 r; i* q - Hibernate: ) n1 \# V2 A* b
- update7 H' S1 a" ]% J+ j+ W* l- T( o
- Teacher ( k7 h! _) [" @# m+ e# K0 B* i' G
- set
8 Z$ ~$ i% P1 x - birthday=?,; O4 l1 U7 P6 \
- name=?,
, M) ]# Q q) J1 L% r' z5 ~! Q - title=? + ^8 X! c8 J% \8 d5 h/ U! B
- where1 y4 D. v# I% ^7 O( ], ~9 ]7 B
- id=?6 } I1 J/ I! |4 F8 N0 d0 N
- 1 r$ y! s+ `1 q# H0 I. e2 W! q
D! ]7 p) O4 u# C6 |" z, W
复制代码
8 m- ]! P4 t# N! H0 T c9 g* K! j5 r* I3 c( V/ ^
执行了2次Update2 u6 T* k- C r D# J
+ z6 P# b1 O# O% y# ~+ ~; `+ }所以看出来flush方法会强制与数据库同步。8 A% M6 n: L, M A
* |/ n' C3 U' X1 {5 Z
3 c6 h' a( M( q' X
Flush方法是可以设置的,也就是fulsh什么时候执行是可以设置的
, o+ u. [: L- k u
. h. q( j+ q6 r2 `' W! _$ l9 N 在session.beginTransaction前设置FlushMode
; o! v6 M$ z1 \. @; ?
: ?# @2 w: ~; j* Osession.setFlushMode(FlushMode.Always|AUTO|COMMIT|NEVER|MANUAL)
( j* D( ?: T2 E, z
/ K! D7 E0 ~( m" x5 \% H$ aFlushMode有5个值可选
: E+ q: G L8 |; G; B/ }2 n9 Z
1 u. j/ [2 d8 q1 U' S9 u7 kAlways:任何代码都会Flush3 ^# d7 r3 w- R4 p! ~* w$ n
AUTO:默认方式–自动% M" _$ c; ^- _7 A
Commit:COMMIT时6 B! k. e2 i8 N$ u- u. X/ _; k
Never:始终不' p/ q( g5 V8 b& W7 H+ I) m
MANUAL:手动方式
, \( N: i4 O) `, D7 f* K% N6 y9 U, F4 r) F
设置FlushMode 有个好处是可以节省开销,比如默认session只做查询时,就可以不让他与数据库同步了。- i1 y5 x9 ~( R$ T! }6 L. j
================================================================
$ |' {5 ]% @- P& g$ ^ G6 q* k我说一下一些需要注意的信息:
4 m4 J/ G# m8 M' ]
0 O* e$ c5 |" }8 {2 [ T+ w5 v1 session.clear()的作用是只清除session中的缓存数据,但不管缓存与数据库的同步。
6 b0 l4 q6 f" s' d" v4 }( J0 A
! w' @9 w4 }4 T7 S& V+ X比如,你执行了
1 V. h$ K3 D) ]6 E, u: O; V! `0 R& K6 P! _; U" Y
Po po = new Po();8 g/ L5 ^+ J8 i$ X/ F
session.save(po),# a" a8 ]$ x1 z
) N! @7 o# a9 D2 W, x1 Q! E# I+ r
之后马上执行session.clear(),在事务结束的时候,这条数据是不会被持久化到数据库中的,因为一般缓存是在事务提交的时候进行清理的,当在清理缓存前就把缓存给清除了,自然就不会同步到数据库了。不过这个也有例外的情况,就是当对象使用native生成器来生成主键id时,当执行session.save()方法时,就会立马往数据库插入一条数据,这时候执行session.clear()也不会影响了。9 c# u5 K0 w/ L& K
- S9 f- e( U. \4 d: T( ?8 M2 当更新或者保存大批量数据的时候,可以每固定数量的时候,进行清理缓存,同时清除缓存:
5 J* l( y2 r, ^, K
2 {+ H( D; I& a1 o6 }for (int i = 0; i < 1000;i ++){% _4 U8 O+ h+ M; V! x& U. K" f* ] H
* s5 b. x( h3 y! ]7 y, r" kif (i /20 == 0) {# U0 c# B4 q& F( v4 s
: N, T; t1 K/ n0 r$ V session.flush();
& O, _( R5 }7 Q# y1 q/ W; E( }
$ p$ V0 c6 u9 P2 u1 L. M session.clear();; v0 X8 a9 A& S6 G& S/ u: O4 o
}
0 ?1 z" q+ Z* R}
& A* ]0 \; b6 W, q v
, x+ ~( |) v9 g; {因为把大量的对象放到session缓存中会浪费大量的内容空间。
( r9 B* Y' n4 u$ a; Q+ c. |# D, H% G
J' y/ R- N1 l7 R0 l; a- l6 A2 D
3 执行完session.flush()时,并不意味着数据就肯定持久化到数据库中的,因为事务控制着数据库,如果事务提交失败了,缓存中的数据还是照样会被回滚的。, e6 \9 b7 n: u8 Q4 M' L5 [
$ E. f) M. u$ ^( D
; E3 M. O, A8 m1 |$ {4 A! y
|
|