该用户从未签到
|
需要启动二级缓存,二级缓存的scope是sessionFactory。也就是说二级缓存的数据可以在由相同SessionFactory创建的多个Session中重用。4 X$ |! O, h* I. ^+ H0 A) s1 ?" c
/ a+ I* Y5 B8 g m) c' a; m6 b首先,要在hibernate.cfg.xml中设置一个cache Provider,hibernate支持多个cache实现,有EHCache,OSCache等。在非分布式环境中可以选择默认的EHCache。添加ehcahe jar# A3 Z; R- b0 p* X, O- ^- d6 M
- <dependency>) Q3 O6 |' M& e$ h6 C
- <groupId>org.hibernate</groupId>
3 k; n2 ?! U8 R/ s0 X, K! V - <artifactId>hibernate-ehcache</artifactId>$ _) r) B: u0 W" E
- <version>4.3.5.Final</version>
6 J6 x( R9 W: V: o' \9 v; Z - </dependency>
复制代码- <hibernate-configuration>
; C% Z t$ S( v, g& z - <session-factory>
5 H: g2 ]- J0 j; t1 a% A3 r - <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
- S. e; q% R; b2 a; F - <property name="connection.url">jdbc:mysql://localhost/test</property>
6 a3 {& ~4 c0 v7 R3 n. J - <property name="connection.username">root</property>
; D0 y- z1 b- i - <property name="connection.password"></property>) m8 w) `- \" o( w3 N- W
- <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>0 ^- k) ~# f$ ~
- <property name="hibernate.show_sql">true</property>6 i! m3 T! D7 |0 D& L. X6 W1 ^. J
- <property name="hibernate.hbm2ddl.auto">update</property>" w" r2 W1 V/ f0 d- i
- <property name="hibernate.generate_statistics">true</property>
4 K, _8 D2 z# t1 z T: }7 z - <property name="hibernate.cache.region.factory_class">
& _7 L# j+ I0 S- r/ [ - org.hibernate.cache.ehcache.EhCacheRegionFactory% R& F5 K! l0 Q8 R
- </property>
! s7 N W8 O _. \+ j) t - <mapping class="com.xinglongjian.entity.hbm.Book2"/>
2 U! z0 L* @% X' C0 W, S* o3 ~! s - </hibernate-configuration>
复制代码
# ~3 d' Q! x; }6 f- x4 d 第二,通过ehcache.xml配置EHCache,该文件放置于classpath的根目录下。可以在该配置文件中设置将不同的对象存储在不同的regions。- <ehcache>9 e0 S5 x0 f* ^6 o
- <diskStore path="c:/data/ehcache"/>
3 j/ `! r H, x6 {+ b/ M - <defaultCache. K9 y: C9 v5 }# f, O
- maxElementsInMemory="10"
! o N3 X4 V4 A1 F, T: M - eternal="false"! g7 I$ P) m8 U7 Z4 U
- overflowToDisk="true"7 Q2 \* E ], u* S3 X8 j$ O
- timeToIdleSeconds="120"
/ N, `0 E5 r3 W - timeToLiveSeconds="120"
8 E& Q M( C! o* e$ ` - diskPersistent="false"- L; Z9 x( c+ a- L/ j/ U3 B
- diskExpiryThreadIntervalSeconds="120"/>- [6 G, w e4 R; Y% I2 F
- <cache name="com.xinglongjian.entity.hbm.Book" maxElementsInMemory="10" eternal="false" . W2 M8 N+ X; ^2 r+ I( y% S
- overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false"/> l& x3 U8 ^8 i/ d& i* C6 ~, t' Q, D
- </ehcache>
复制代码 第三,设置持久化类- @Entity
$ ~2 R1 `4 j- e3 S4 S- Z7 A- h8 [ K - @Cacheable
C1 b' B7 K/ f6 G3 A' j - @Cache(usage=CacheConcurrencyStrategy.READ_ONLY,region="com.xinglongjian.entity.hbm.Book"); Y% s1 J E/ W: Z' g9 c) m! L5 B
- public class Book2 {! B' P: t7 J* a5 S
- @Id
D. v) e( v5 {/ n% z2 d! G - @GeneratedValue6 M; T5 b9 ]3 N! Z$ i/ U- k$ M
- private int id;
) A( x- |' N$ Q ~ - private String title;3 f$ ]4 ?, s# f+ E1 {! A4 a
- public String getTitle() {( t/ t/ j0 U& k7 Z6 j
- return title;
$ U+ w. S" M% ~6 Q k - }* W/ s" s1 X; P7 e, N
- public void setTitle(String title) {
+ v( D0 J+ I6 d- l1 l @ - this.title = title;
0 r( l, B( v; U" h/ t - }' A% ^- J: W& c) w1 W* J0 q
- public int getId() {
1 M+ ~# ]% m7 s8 E - return id;9 C7 j0 ~$ I6 w& p/ y* S( U T2 }9 A
- }
* G: u; }0 I5 E, \ D+ q2 L9 E - public void setId(int id) {
$ R; P; S) q5 Q' U4 { - this.id = id;. \5 w" q% H; A/ N. K/ V
- }9 ^' A3 _% `: J5 I* v1 J" v9 p# M9 l
- @Override
" g% u' k2 G- ~) F - public int hashCode() {3 b+ w# i3 e8 K7 N: t( H
- final int prime = 31;& x2 k8 l a: n Y) A" S' V
- int result = 1;
& `; Q5 l' F* z - result = prime * result + id;/ j0 {" ]" W7 ^3 O2 A
- result = prime * result + ((title == null) ? 0 : title.hashCode());- h" |% O% m6 J6 p4 |
- return result;
2 q) R$ f1 C& ^ - } S/ c6 Q8 r5 r q0 ?% K8 [
- @Override+ g" T0 Y* o3 L* U* a
- public boolean equals(Object obj) {
- l+ Z+ @* c1 U: L7 O3 L3 e - if (this == obj) ]( T% E5 z1 K9 U9 y
- return true;
8 w- e/ n& v% N - if (obj == null)! d5 B) y: m L. c
- return false;1 r! ~( ~. l; A6 H
- if (getClass() != obj.getClass())7 H) }. V5 f- ~0 E6 l) A
- return false;
. g9 w/ S0 V% o% j8 g7 h - Book2 other = (Book2) obj;$ s8 {$ t+ ]! \6 [
- if (id != other.id)8 w3 p2 j/ _: G& u
- return false;
& R0 g! G0 Q, i1 @ - if (title == null) {; {7 Y. ^1 s; |; \$ T2 c
- if (other.title != null)5 d* C7 z$ V! R8 z. r
- return false;$ M: {) p# d- V: p( g
- } else if (!title.equals(other.title)): e* L2 f2 S* @
- return false;0 w- {. b+ B) \' o
- return true;8 @) E$ f6 H0 C' E, }* v
- }
/ P+ F+ M K2 z y - / s) W: q- X" L: i$ k; E5 q
- }
复制代码 二级缓存的持久化类必须实现equals方法。
& K O q4 \" n+ L2 _* w' ~$ j1 Y
& w" {$ ^/ L- r9 }只有在SELECT时才会缓存。; U. {; t s% Z/ N/ K p
) e' C* d- ^7 u2 H6 Y' A: D3 _在同一个session里,查询2个不同的对象,会缓存2次,- Session sess=sf.openSession();9 e" D3 j2 b/ B9 F# ]; m: o- T
- Book2 b=(Book2) sess.get(Book2.class, 17);
9 y E! n1 B# @ s2 W - System.out.println(b);
9 I4 R* |, x+ \% }: T- D - assertEquals("spring Recipes", b.getTitle());
~; i& l' E- K3 O$ ~7 p - Book2 b3=(Book2) sess.get(Book2.class, 18);
, k' T1 l' `3 V- Q& D! t4 L - assertEquals("dfad", b3.getTitle());
- _, W# U/ M' r4 R0 D9 l$ A$ T4 h - sess.close();
/ Z. Z6 i; P. r# L. c. N/ i, Z - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");4 D' c) E( w3 ~# Z: @7 s) D7 M$ \
- System.out.println(slcs);
复制代码 结果- SecondLevelCacheStatistics[hitCount=0,missCount=2,putCount=2,elementCountInMemory=2,elementC+ U r+ | z: B/ P+ V" F- G
- ountOnDisk=0,sizeInMemory=3948]
复制代码
h7 n9 [1 y1 X$ y/ E9 w 在同一个session里,查询相同的对象,会先查询一级缓存,一级缓存中有就不会查询二级缓存。- Session sess1=sf.openSession();1 e. |4 E8 S' v) g
- Book2 b1=(Book2) sess1.get(Book2.class, 17);
& `- c& ~' d4 A2 p - System.out.println(b);* e7 X# g! P* E. b; K4 G3 i6 v4 T" W
- Book2 b2=(Book2) sess1.get(Book2.class, 17);
" [1 ?. [3 L2 q2 u% o - assertEquals("Spring Recipes", b1.getTitle());' w& j2 Q9 ?5 p. |* u
- assertEquals("Spring Recipes", b2.getTitle());8 \" u0 ^# D* J1 f
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");! k! S0 V; n: {/ f$ E; z! n2 s
- System.out.println(slcs);
复制代码 结果,在新的session中,一级缓存不可用,就会使用二级缓存。- SecondLevelCacheStatistics[hitCount=1,missCount=2,putCount=2,elementCountInMemory=2,elementC* Q5 I7 q5 k5 X& M$ X% T
- ountOnDisk=0,sizeInMemory=3948]
复制代码 完整测试逻辑- @Test/ _/ d: Q+ u8 B) R
- public void test2LCache()
3 P) u& @1 r/ P - {: F8 b: }+ ^4 |( k! M7 |6 V
- Statistics stat=sf.getStatistics();//获取stat对象
' D' ]/ D# s- D+ G% ]. ?3 S - Session sess=sf.openSession();7 w7 Z x T1 m" I8 F
- Transaction tx=sess.beginTransaction();
- O+ s; A! W) @7 H - # K7 E3 b! ]7 t# G" A2 J* M, g
- //存储对象,此时不会放到缓存中
; {) u7 [3 A3 R; q6 n B! {( b - System.out.println("--------------存储对象---------------------------------");) V% ]8 k5 U. G* M* V
- Book2 book=new Book2();. |" J, n7 b0 o4 o% Q! b6 @0 ~# l
- book.setTitle("Spring Recipes");
$ e6 c; M. w { - sess.saveOrUpdate(book);5 Q3 u; |5 d9 L3 ~& z0 S
- tx.commit();
! Y5 X* `2 T8 R7 h$ [. @; q - sess.close();5 J) J1 e! R. C1 j0 p1 c
- System.out.println(book);
) C8 C! Q& R) T2 \" i - SecondLevelCacheStatistics slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
/ Y6 b1 g5 S. L - System.out.println(slcs);- ^7 F. E/ K0 K/ c% I! r
- Cache cache=sf.getCache();
* F3 W4 H: }1 F0 t% z8 U0 d - System.out.println(cache);
|) D9 H% Q( @7 P+ E - cache.evictAllRegions();//从所有region中获取数据" }* c7 i' [! s: _0 q Z
- Map map=slcs.getEntries();; o0 j) L0 i9 p& m$ }& x1 K
- System.out.println("Cache entries:"+map.size());
v7 q6 `1 y+ G+ h - System.out.println("--------------第一次查询后---------------------------------");
" p. W0 o( I0 N0 y8 A4 ^7 J - sess=sf.openSession(); b4 W6 c% q1 }
- tx=sess.beginTransaction();
9 x1 g/ w' v2 x5 h% k4 P - Book2 b1=(Book2) sess.byId(Book2.class).load(book.getId());//第一次查询' G& ~3 h, h1 Q2 l! d% H" K9 N
- System.out.println(b1);( I0 c% m4 k3 R, R% x
- assertEquals(book, b1);
( H6 o. @* g* ~4 E5 [ - tx.commit();
# K8 k+ B" o9 V2 U+ m - sess.close();; _2 w0 ?' v/ |, G* p8 C( v' P! ]
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
# o) p8 Y# x" A v, G: Y. [/ s9 d - System.out.println(slcs);; X, ?4 H" x1 n
- map=slcs.getEntries();6 k' {) b* C0 p4 i
- System.out.println(map.size());
; F' k+ i R0 i4 J6 J1 \ - System.out.println("--------------第二次查询后---------------------------------");5 `* X6 r6 G5 H/ K: B
- sess=sf.openSession();3 u4 ^, k, q) J+ h; Z$ e9 @( A# F
- tx=sess.beginTransaction();
0 |7 [3 c9 R7 y$ h6 u! @5 C - Book2 b2=(Book2) sess.byId(Book2.class).load(book.getId());//第二次查询% B$ Y. n% k1 \2 M
- System.out.println(b2);
* M- X: h' J8 s6 V$ b3 D! v - assertEquals(book, b2);
z1 G$ o# R8 [: R) W7 ] - tx.commit();& _/ _( y0 E8 V6 _
- sess.close();
: l" V4 o: S* u! ?& u( L+ b -
, Q8 A; @$ [. V2 Q - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
' D- c. ?" K# ]2 |( W - System.out.println(slcs);9 y3 j% J. v# R! i
- // this is the initial select
! O% W* T' _. ` - assertEquals(stat.getSecondLevelCacheMissCount(), 1);
' j1 U4 v6 [2 l# N2 d& E3 W2 Z - // we put one element in the cache from the miss
5 K7 `. ?8 [6 T* ^! k4 u - assertEquals(stat.getSecondLevelCachePutCount(), 1);
+ j. I ^* R/ e& F5 c# q - // we still didn't hit the cache, because of 1L cache+ F+ L* U3 F7 a- {( W8 _! Q
- assertEquals(stat.getSecondLevelCacheHitCount(), 1);
" O: b; m; D; o6 n - System.out.println("--------------第三次查询后---------------------------------"); F! X1 k7 X$ V: |
- sess=sf.openSession();
: U8 W* w& X$ r- |. q, T# m) O. @ - tx=sess.beginTransaction();
. B5 T/ V( @5 @7 k) y6 e5 Z - b1=(Book2) sess.byId(Book2.class).load(book.getId());//第三次查询* c% W) j! J4 `5 k7 t' S
- assertEquals(book, b1);
% e: i$ h- D+ R# ^: `: f6 V: H) @ - tx.commit();
- H, C }* k1 v. r- I; C - sess.close();# t) s2 ^1 M5 T' t) B
- 6 `1 P" }8 n- m, a _; o
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");/ I$ n4 G$ b1 n# I2 d3 o9 _
- System.out.println(slcs);
8 U; @: C! ^2 p& L$ M: L - // same miss count (we should hit now): ]& m! r. f1 D: f- V
- assertEquals(stat.getSecondLevelCacheMissCount(), 1);/ l' Y+ i. m8 `9 S o
- // same put count (we didn't put anything new)/ e; [. M9 e7 m5 [4 D
- assertEquals(stat.getSecondLevelCachePutCount(), 1);, i3 E! A9 I$ v5 ?
- // now we hit the 2L cache for load
4 o+ ?( g- j( }: x4 D8 D v - assertEquals(stat.getSecondLevelCacheHitCount(), 2);
, d5 ]2 h/ P2 k. ^, B - 4 `3 k8 {( N$ F, d
- }
复制代码 完整测试结果- Hibernate: delete from book2
* F" W O# O8 m: E& C. S% e0 b# W - --------------存储对象---------------------------------
+ s* A: p2 i& W2 E$ b( b% |" P7 ? - Hibernate: insert into Book2 (title) values (?)
+ x u/ j D; ~7 l7 u. L" C$ E - com.xinglongjian.entity.hbm.Book2@521e083b
! w0 H0 l5 ~2 l% f& }/ G - SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=0,elementCountInMemory=0,elementCountOnDisk=0,sizeInMemory=0]
" |$ k0 P! P1 h. [9 r) }# G8 x - org.hibernate.internal.CacheImpl@4830f68 o* q' I9 q$ I" v! E }
- Cache entries:0/ p* F+ a1 Z) \- G1 x1 M
- --------------第一次查询后---------------------------------
: v4 Y6 }/ |4 M* m* ~) g. k - Hibernate: select book2x0_.id as id1_0_0_, book2x0_.title as title2_0_0_ from Book2 book2x0_
2 t5 j, S5 P) @% j - where book2x0_.id=?
) V) t8 f1 J1 F& L' |9 D4 g - com.xinglongjian.entity.hbm.Book2@521e083b e- q) h& J( [" h% L) G( B
- SecondLevelCacheStatistics[hitCount=0,missCount=1,putCount=1,elementCountInMemory=1,elementC
6 s$ H! m0 j- s* Y - ountOnDisk=0,sizeInMemory=1979]5 D7 m& J g u) H* Q
- 15 ?3 S: k9 q- c3 i! h. W
- --------------第二次查询后---------------------------------! {: Q/ N8 f) k7 J8 g+ r1 N2 R
- com.xinglongjian.entity.hbm.Book2@521e083b( H& j: |$ Q( i" V, c8 p9 M' M6 w
- SecondLevelCacheStatistics[hitCount=1,missCount=1,putCount=1,elementCountInMemory=1,elementC/ d$ ^7 s# D) C/ E0 N2 K
- ountOnDisk=0,sizeInMemory=1979]3 D1 k* ]: A8 H6 L8 m% d
- --------------第三次查询后---------------------------------
7 V h9 X% }, q. L - SecondLevelCacheStatistics[hitCount=2,missCount=1,putCount=1,elementCountInMemory=1,elementC: y/ ?0 z' }: J4 f( ~* Q! H* I
- ountOnDisk=0,sizeInMemory=1979]
复制代码
% ]9 E& C2 d5 b |
|