该用户从未签到
|
需要启动二级缓存,二级缓存的scope是sessionFactory。也就是说二级缓存的数据可以在由相同SessionFactory创建的多个Session中重用。2 A8 W# G7 E; V, A
6 F8 [& J+ w! \. b8 V2 i6 X首先,要在hibernate.cfg.xml中设置一个cache Provider,hibernate支持多个cache实现,有EHCache,OSCache等。在非分布式环境中可以选择默认的EHCache。添加ehcahe jar9 H/ `7 n) j" O3 t
- <dependency>! c! K$ s# Y0 [+ o0 B+ a e# ]( }
- <groupId>org.hibernate</groupId>" N0 Y2 p. L5 `$ Y9 ]# J4 H
- <artifactId>hibernate-ehcache</artifactId>+ M9 o; W$ {/ a2 K
- <version>4.3.5.Final</version> Q4 K T" d; E8 p% o
- </dependency>
复制代码- <hibernate-configuration>7 ^) O, P( N a
- <session-factory>5 K# i3 T$ v, A3 a7 R
- <property name="connection.driver_class">com.mysql.jdbc.Driver</property>4 }& i& S+ E1 O' z
- <property name="connection.url">jdbc:mysql://localhost/test</property>
5 C# o, Y: X% W2 m: A7 r - <property name="connection.username">root</property>$ b$ v8 j. ` f- k
- <property name="connection.password"></property>
; Z) b7 l% ]2 Q, b - <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
; q& |) R3 f; N7 ~ - <property name="hibernate.show_sql">true</property>' d& F" Y: z5 k4 |+ L
- <property name="hibernate.hbm2ddl.auto">update</property>9 e% R" C& v7 r6 t0 l1 ?: C
- <property name="hibernate.generate_statistics">true</property>
& F- ?$ `+ @3 O0 p# D - <property name="hibernate.cache.region.factory_class">
! R: y \% t: Z, v# U5 G7 U! P' Z1 ]2 D - org.hibernate.cache.ehcache.EhCacheRegionFactory/ h, O3 {9 ]0 U I& A8 J3 A+ T
- </property>" s: m8 L' m0 I9 G5 G |
- <mapping class="com.xinglongjian.entity.hbm.Book2"/>! O e+ \! f: f1 J
- </hibernate-configuration>
复制代码
" T# C( w% S* X s2 u! w 第二,通过ehcache.xml配置EHCache,该文件放置于classpath的根目录下。可以在该配置文件中设置将不同的对象存储在不同的regions。- <ehcache>9 o, f, O) {+ w
- <diskStore path="c:/data/ehcache"/>+ R1 F6 }2 R0 y0 o& W
- <defaultCache' x6 H3 Z4 C- ?" d M8 \
- maxElementsInMemory="10"8 j9 M# h8 i# _& O9 `
- eternal="false"& Q% Q+ H8 z, y9 E$ R1 D
- overflowToDisk="true"- |+ u8 m% s; {
- timeToIdleSeconds="120"
% f2 i' ^. a: `. d" ]7 X - timeToLiveSeconds="120"* f0 a" M3 u( s |$ |" s1 t
- diskPersistent="false"
9 z9 X7 r( F8 ^* A% v6 h - diskExpiryThreadIntervalSeconds="120"/>5 y+ D+ e; A( e5 v' B
- <cache name="com.xinglongjian.entity.hbm.Book" maxElementsInMemory="10" eternal="false"
3 d! h1 U0 l( O& ]* J- b$ B - overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false"/>
" n. J6 @% X6 Q+ k - </ehcache>
复制代码 第三,设置持久化类- @Entity
N9 p5 m" [& ]0 \0 v$ Y: _6 @" t) j - @Cacheable
. w/ G! P6 u. g. a) D - @Cache(usage=CacheConcurrencyStrategy.READ_ONLY,region="com.xinglongjian.entity.hbm.Book") F, e; y* U0 j! H r! O! p k$ h' n% F
- public class Book2 {
4 l+ I0 k( F- I( }& L/ }# W& x% I9 Z - @Id
9 S& z2 k. p8 P: H - @GeneratedValue2 }; r7 U. C: Z
- private int id;
) y1 h- V0 C2 {. L- R, l7 r - private String title;
: o$ Q* x, \6 I# Z! y - public String getTitle() {! P9 B0 Y" Z7 B
- return title;7 e, x; k1 D4 Z. I6 g
- }
$ m1 Z9 x" \) Z1 e - public void setTitle(String title) {
1 Q6 i: C! t3 W; }+ v - this.title = title;
0 `; L* y. y% ]- Y! O2 e* C R - }
1 h0 K- c( q5 D% v6 L# F0 R7 c$ Q - public int getId() {) E8 @3 a. R9 {9 F
- return id;3 }0 s r! r1 i- I
- }
3 L H. a2 r# T& u1 D" W - public void setId(int id) {
5 v' N: p7 G4 v8 m$ k2 m - this.id = id;5 T3 e! l. h/ r+ ?' U0 G' d9 q4 G
- }+ C: h3 _5 Y' e" u* _
- @Override( a* F" z' ~8 D) @0 a
- public int hashCode() {8 A) l5 V6 ?, q' e
- final int prime = 31;5 W4 p2 X& r& X) _) H* C/ b& N
- int result = 1;
8 p7 H* t" p/ i1 x0 a! Z - result = prime * result + id;
$ X0 t s5 ^0 L$ j - result = prime * result + ((title == null) ? 0 : title.hashCode());
. [0 M: e2 ?3 m7 I u - return result;' `3 W2 \/ n- A3 u# P! E
- }; H( H% t3 p+ f3 |
- @Override! B0 w0 \+ w2 Z1 L" W) F
- public boolean equals(Object obj) {& D4 e: N7 G% G" u A
- if (this == obj)
" K- }3 W- o. X5 t! L. H - return true;
% I, t0 l+ s& k- O- }& H - if (obj == null)
. s ^7 D; m' o5 F, A: K - return false;
- S# H# H" `$ p. O! m1 \) f6 k% W7 q0 G - if (getClass() != obj.getClass())
' ?* E5 a$ @% n9 z; z - return false;
2 E8 T7 G) L, |5 ]" y( D; W - Book2 other = (Book2) obj;* t* `8 T" d: }/ e
- if (id != other.id)0 `# K5 y6 G" _
- return false;1 o: q, N8 q) [3 Q o& J
- if (title == null) {
6 }0 _! f& ]& \7 l' L+ Z - if (other.title != null), I8 }6 v M1 E
- return false;' i+ H! Z5 g+ ?% e2 R
- } else if (!title.equals(other.title))
( k9 N$ _) q3 ~2 y: F1 z) n8 V i - return false;3 V0 j. B9 s; A
- return true;! e) }+ P# C( ~6 _. U }8 g% d
- }& p( g F( l J$ z* U8 x
-
3 X8 I9 l) E3 n% e( D2 S - }
复制代码 二级缓存的持久化类必须实现equals方法。7 n6 B% t9 q& K
& Y/ y/ O7 S/ [( D
只有在SELECT时才会缓存。
* V1 J8 M: S1 H# h0 T+ Z- n9 N8 ]- R: a4 y
在同一个session里,查询2个不同的对象,会缓存2次,- Session sess=sf.openSession();& I* t1 N: P9 W6 P+ n" L
- Book2 b=(Book2) sess.get(Book2.class, 17);
4 V: I d3 P- M, `: J - System.out.println(b);
! W7 O( C( _$ ^/ D4 ?4 } - assertEquals("spring Recipes", b.getTitle());+ g. x) J" s, x! c- O# k8 w
- Book2 b3=(Book2) sess.get(Book2.class, 18);" v" x& x9 n9 y, a4 ^$ P
- assertEquals("dfad", b3.getTitle());0 s' g* d) g% v" A V
- sess.close();
3 K$ _5 h6 c. }4 x' P3 Q$ _. v5 E - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");- `6 m7 j1 [- {/ |+ ?
- System.out.println(slcs);
复制代码 结果- SecondLevelCacheStatistics[hitCount=0,missCount=2,putCount=2,elementCountInMemory=2,elementC
4 W- i" p( F2 }" t9 {2 A* e - ountOnDisk=0,sizeInMemory=3948]
复制代码 - Q) B1 e9 w$ o7 K2 a1 K
在同一个session里,查询相同的对象,会先查询一级缓存,一级缓存中有就不会查询二级缓存。- Session sess1=sf.openSession();$ ~8 b$ e7 L. R" A+ f; E5 d' G
- Book2 b1=(Book2) sess1.get(Book2.class, 17);
, j. y7 M. W1 G/ r' U - System.out.println(b);
. `; q7 A8 k/ y P% U6 T - Book2 b2=(Book2) sess1.get(Book2.class, 17);
9 U/ S/ B( n- y6 u7 P9 d1 @: _ - assertEquals("Spring Recipes", b1.getTitle());& g1 C2 `( `& h: {6 X) h
- assertEquals("Spring Recipes", b2.getTitle());
+ w, b# ~4 h1 p - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");8 U: @7 v8 |' P
- System.out.println(slcs);
复制代码 结果,在新的session中,一级缓存不可用,就会使用二级缓存。- SecondLevelCacheStatistics[hitCount=1,missCount=2,putCount=2,elementCountInMemory=2,elementC
# Y( ~" G% E% W6 [ - ountOnDisk=0,sizeInMemory=3948]
复制代码 完整测试逻辑- @Test7 X4 w+ w& b/ Z% [2 n- v
- public void test2LCache()
; a: G; G3 W( m2 R7 J8 B - {
0 a% R& @) x8 ] o6 |# B2 ? - Statistics stat=sf.getStatistics();//获取stat对象
% K7 v F' [ D - Session sess=sf.openSession();$ _* Q' v- P1 s+ Q- }& }9 q
- Transaction tx=sess.beginTransaction();
: g, {3 m9 B9 N5 ?( L -
2 k B" Z! q Q9 x" C# A - //存储对象,此时不会放到缓存中- P$ L9 E# ]: J* o
- System.out.println("--------------存储对象---------------------------------");
5 R- G6 t/ e) B" m- I& O# |, j/ F - Book2 book=new Book2();, I/ t9 u) X* @, k1 @
- book.setTitle("Spring Recipes");
6 w* H+ i/ e7 b6 w2 p - sess.saveOrUpdate(book);
+ S- z7 a. [5 @. ~* ?4 ? - tx.commit();* J$ R- a7 A; i5 ?1 k5 N4 p
- sess.close();
% `5 c5 f- m8 m# s& A. K9 d - System.out.println(book);
. i% A$ U+ ~% G6 p4 O! P# E% G% |6 f - SecondLevelCacheStatistics slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
! t! g( {% F8 u( L/ ^" A - System.out.println(slcs);
- u* U% D. {1 ?1 w, e; M' U+ k c - Cache cache=sf.getCache();" a1 r- r; J- Q/ [7 v; e
- System.out.println(cache);$ h$ `3 M; y1 p7 j- B3 O
- cache.evictAllRegions();//从所有region中获取数据1 e! O0 `/ c5 `) k
- Map map=slcs.getEntries();4 G& D6 @( O$ m' j5 M% m+ Y- ^) O: D
- System.out.println("Cache entries:"+map.size());1 j% u- t- Y* ]0 T4 d( x
- System.out.println("--------------第一次查询后---------------------------------");
. m% C5 c' `% a* X - sess=sf.openSession();/ P7 h# @+ U8 p, I1 f1 y/ H) y
- tx=sess.beginTransaction();* V0 I" x" P+ M2 q# o
- Book2 b1=(Book2) sess.byId(Book2.class).load(book.getId());//第一次查询
/ L% D3 h p: w6 q - System.out.println(b1);
6 e7 w* d) ?/ h# U/ @% W& m - assertEquals(book, b1);* A5 V! f& x" A! g8 }1 d7 l, ?
- tx.commit();
7 l. o$ d+ T* {' c- J8 ? - sess.close();6 S6 y7 n/ C# h: W* k$ L5 B
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");% }* d: }& ~6 J" n8 i; q3 {& @
- System.out.println(slcs);
8 X, J- T# m3 a" \$ h; b - map=slcs.getEntries();1 s6 _9 ]. r0 F4 O, j4 O
- System.out.println(map.size());
% @1 s7 N$ ~' i y - System.out.println("--------------第二次查询后---------------------------------");7 a" M' ^/ {: _9 Q7 R: _% w% L
- sess=sf.openSession();# E+ B$ ]7 j5 ?
- tx=sess.beginTransaction();, w& c# ~! a8 k. w
- Book2 b2=(Book2) sess.byId(Book2.class).load(book.getId());//第二次查询: M( N! [8 s$ h6 u
- System.out.println(b2);
9 V% j7 S. C3 B# h - assertEquals(book, b2);2 K& r# _8 X0 s$ g+ e
- tx.commit();# u% W( [) J, Q- K4 U! x! ]
- sess.close();
/ J: S! d+ }& q5 g0 p$ A -
: g6 b0 r" a6 u - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");6 y; Z/ W9 H5 E6 K A) N" [
- System.out.println(slcs);6 ~( \3 U3 H: o. e
- // this is the initial select
+ V* O k( v1 A5 Q% \. O+ z - assertEquals(stat.getSecondLevelCacheMissCount(), 1);. D9 k6 L1 y6 |5 w: d7 W
- // we put one element in the cache from the miss. D- X2 Q: h7 p5 e+ i( I
- assertEquals(stat.getSecondLevelCachePutCount(), 1);
; A2 v2 z% [0 C6 ]- p - // we still didn't hit the cache, because of 1L cache
) e/ }# x4 n: _8 h - assertEquals(stat.getSecondLevelCacheHitCount(), 1);
! E- h4 Y `7 Y8 z/ _3 T - System.out.println("--------------第三次查询后---------------------------------");8 a2 E; _" \# l* J8 L
- sess=sf.openSession();+ L) H/ A9 w; z- M
- tx=sess.beginTransaction();
1 v2 L) ?, {* N" y' t: o - b1=(Book2) sess.byId(Book2.class).load(book.getId());//第三次查询5 A% J: E" {" e( y
- assertEquals(book, b1);
: R7 m$ E: t$ i# j2 N1 J - tx.commit();
' N+ e" a( F4 C' `! T! U - sess.close();3 D w; A/ a2 A) Q3 V- a7 M! s
-
4 {( ?2 V+ S- Z9 F4 {# D' } - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
3 [0 A* Y0 z) T3 s6 S# m - System.out.println(slcs);/ R2 i! e& n; Y4 T! M: F, m5 m
- // same miss count (we should hit now)
8 C0 O& o; @3 H) o" M9 I& a. i - assertEquals(stat.getSecondLevelCacheMissCount(), 1);& z! `# j* d& P: S' s( U# E. R
- // same put count (we didn't put anything new)& o. n. d# ?8 r3 F. B$ k O
- assertEquals(stat.getSecondLevelCachePutCount(), 1);
3 D. h" v! b6 ?: {4 Y2 G - // now we hit the 2L cache for load
) ~$ G; B& D" h - assertEquals(stat.getSecondLevelCacheHitCount(), 2);
8 n" @! ?3 p4 j - " w% ?5 h, ?8 m8 ]( R6 c
- }
复制代码 完整测试结果- Hibernate: delete from book21 e ~2 C$ H/ V' }/ j' n
- --------------存储对象---------------------------------
$ g* e/ n" Q9 n* ~ - Hibernate: insert into Book2 (title) values (?)# T( m: `8 K" {% U6 ^
- com.xinglongjian.entity.hbm.Book2@521e083b
8 o3 I0 e* [3 `: \: f7 \ - SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=0,elementCountInMemory=0,elementCountOnDisk=0,sizeInMemory=0]$ N( j$ v) Q! u8 T) O/ H9 K6 Q
- org.hibernate.internal.CacheImpl@4830f6
* A% e# V' R% L4 h - Cache entries:0
+ G. e+ e9 ]4 T+ z - --------------第一次查询后---------------------------------+ E6 R$ Z& O! K& ~
- Hibernate: select book2x0_.id as id1_0_0_, book2x0_.title as title2_0_0_ from Book2 book2x0_3 G* c, Y% p* C7 n3 }
- where book2x0_.id=?
; m% l( g2 i/ M# `+ [: m; K) @ - com.xinglongjian.entity.hbm.Book2@521e083b
" o3 a$ G, S# Y) R% ^ - SecondLevelCacheStatistics[hitCount=0,missCount=1,putCount=1,elementCountInMemory=1,elementC- z, m' W2 C w8 O' c2 R* r. y
- ountOnDisk=0,sizeInMemory=1979]
" y% U5 D" u, Z- u$ z - 1
; C+ A! p0 ? l5 Z+ l4 T - --------------第二次查询后---------------------------------) a* Z, C$ e7 O. R
- com.xinglongjian.entity.hbm.Book2@521e083b
" Y& T( \2 M* Y" C+ T! ~ - SecondLevelCacheStatistics[hitCount=1,missCount=1,putCount=1,elementCountInMemory=1,elementC6 F$ A8 G/ m% I$ j
- ountOnDisk=0,sizeInMemory=1979]1 E; H! Y- Z; l9 E, r6 j' E
- --------------第三次查询后---------------------------------' `3 ~$ i0 S( I; b6 Q
- SecondLevelCacheStatistics[hitCount=2,missCount=1,putCount=1,elementCountInMemory=1,elementC
! {7 {- x: F( ?) ?, c: U0 j5 R - ountOnDisk=0,sizeInMemory=1979]
复制代码
7 B# e. L* b' a1 ~; c |
|