该用户从未签到
|
需要启动二级缓存,二级缓存的scope是sessionFactory。也就是说二级缓存的数据可以在由相同SessionFactory创建的多个Session中重用。% R9 i7 Q) O+ j3 e$ \
* L7 z9 g0 s; q9 {% d6 v
首先,要在hibernate.cfg.xml中设置一个cache Provider,hibernate支持多个cache实现,有EHCache,OSCache等。在非分布式环境中可以选择默认的EHCache。添加ehcahe jar
! C7 N6 i2 U$ D3 _. i- <dependency>0 Q) m. Q$ f+ T7 A# S9 L$ T# e
- <groupId>org.hibernate</groupId>+ o8 t4 Y* Q% @0 l. {5 T* G
- <artifactId>hibernate-ehcache</artifactId>
1 @3 p9 }; R2 a: S. P - <version>4.3.5.Final</version>
( } ~1 \! }# D6 v: u$ s) ?/ d - </dependency>
复制代码- <hibernate-configuration>
& i# T& l) Q3 M$ k" Y( `" A+ t - <session-factory>
' ?: |- H6 z" R - <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
& W& ?" s! \, C/ L/ y* t- E - <property name="connection.url">jdbc:mysql://localhost/test</property>
2 L; w, q2 h3 D2 Q) A: m8 a - <property name="connection.username">root</property>. ^8 o9 x! |1 O9 z" _9 u/ a3 ^
- <property name="connection.password"></property> B+ [, @" O' G+ p7 w) m0 c
- <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
' A* b" Z# k( ^) ~# @ A; ]( V - <property name="hibernate.show_sql">true</property>$ l/ Z5 h! X T" K
- <property name="hibernate.hbm2ddl.auto">update</property>
! O1 a1 V$ c3 U% j3 b& l$ s - <property name="hibernate.generate_statistics">true</property>2 N) i) O' |$ v6 a& C% B s
- <property name="hibernate.cache.region.factory_class">0 H0 I! p' \" N- `
- org.hibernate.cache.ehcache.EhCacheRegionFactory
4 p- A' Q: T, z5 N - </property>
+ O: W! I& X/ S# U4 {( o" n - <mapping class="com.xinglongjian.entity.hbm.Book2"/>$ W- t0 t2 z8 Y! g0 T' N
- </hibernate-configuration>
复制代码 " ^0 S8 n% i6 |2 H) f7 U
第二,通过ehcache.xml配置EHCache,该文件放置于classpath的根目录下。可以在该配置文件中设置将不同的对象存储在不同的regions。- <ehcache>
1 `8 i* M" t2 \8 d7 w7 Z0 Z - <diskStore path="c:/data/ehcache"/>
+ ~% `) T" L: U$ C - <defaultCache
3 l: U: R- c3 t# E2 f - maxElementsInMemory="10"
; {+ O+ `% N3 D) X- @7 ] - eternal="false"
3 ~/ ?7 q/ n4 `6 q! Z" D. H - overflowToDisk="true": k( E: t" [2 q6 l
- timeToIdleSeconds="120"
' d3 m1 E0 J) W/ A7 V - timeToLiveSeconds="120"2 d( U) u0 ?; j" @, N n" J6 Z
- diskPersistent="false"
# r" H; b! q2 B! k5 M: l1 {# U; R - diskExpiryThreadIntervalSeconds="120"/>
, I3 c5 S, I f$ S - <cache name="com.xinglongjian.entity.hbm.Book" maxElementsInMemory="10" eternal="false" 0 R$ e2 w: l4 J7 {
- overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false"/>
6 u4 g+ O( u7 L, M, P - </ehcache>
复制代码 第三,设置持久化类- @Entity
" V+ y2 d) T7 H$ i0 f a. y - @Cacheable
8 [& S/ ^8 n$ V9 T5 G) E - @Cache(usage=CacheConcurrencyStrategy.READ_ONLY,region="com.xinglongjian.entity.hbm.Book")* o' R! s1 |2 u4 d9 P9 h, E
- public class Book2 {* M7 o; c* ]$ d
- @Id
/ m7 _, b4 ~1 ?, r& G) `7 x - @GeneratedValue+ G7 ^/ [ r d$ B/ a$ E! d
- private int id;
/ R. k* C0 R0 {& ~' R6 k - private String title;7 ]. H1 ?7 h0 ^ N% S- N5 C
- public String getTitle() {
3 V, Q- _# j% h% h% D - return title;
+ a* y' O, \2 M& f7 `) b9 A: v - }
9 s) V4 M) p9 v2 {2 } - public void setTitle(String title) {
6 J% a5 A% Y3 m; m - this.title = title;/ W( Q4 t6 o- f! t( [- s
- }
4 |' T( q- h) Z# K - public int getId() {) E- `* @$ ]! T A5 ~ I) f8 P/ `
- return id;
7 l8 ~, }5 R" Z* \7 T0 J) Q' N - }
" z# X, m4 S8 E; v6 e2 t - public void setId(int id) {
+ F4 {. K6 n; c U! p - this.id = id;
9 A, t( d! c* w2 |5 U - } [% @1 l( P( t0 L
- @Override
) A( _# s$ M4 [; ^ - public int hashCode() {+ B# L" _! h6 }% X8 a, ~( z% S" }
- final int prime = 31;
4 ~7 z; |" k0 f! d) ]! T+ w - int result = 1;9 ~. \+ S% `# T
- result = prime * result + id;
3 D: G) P1 Y# c+ w' ]/ W - result = prime * result + ((title == null) ? 0 : title.hashCode());: B/ ^* r4 T: f% o+ d( C3 w
- return result;8 v8 ? n N; Z' f& n0 V
- }4 p% @; G, T- n; p& ~7 Y+ g+ q
- @Override
9 v5 X7 ?+ l5 ^ m4 h - public boolean equals(Object obj) {1 z, ?/ f h: k4 x( P+ l' X- B( _0 b
- if (this == obj)
$ h9 e7 r, E) E; E- k - return true;
( g& l2 y% U0 @0 O1 V s - if (obj == null)9 X# \3 }( I: X: u
- return false;3 E& S/ o- Y/ F& H; X0 Z R
- if (getClass() != obj.getClass())3 B+ M# W2 `+ r! n" ^
- return false;
- ^ R, w9 m1 t6 }2 F7 { - Book2 other = (Book2) obj;+ n3 B+ k2 `/ r
- if (id != other.id)
7 M7 r5 G4 d( `7 h( f/ K - return false;4 z Y/ J$ y3 |- o; I" a5 d
- if (title == null) {
4 j* S4 m" ^, Q+ }$ U0 a - if (other.title != null)
" X4 u0 ]9 s1 p6 Q3 f% d - return false;( Z7 w. v7 y* O0 m" X
- } else if (!title.equals(other.title))
# L. ?( @& ~' E7 q5 i" z - return false;* I) Q2 x- R/ ~3 X4 g
- return true;8 z0 @3 C8 n( a+ _. c
- }2 y5 i, o O5 n B
- 1 }3 }. c4 g& a9 E3 i1 O% f% q
- }
复制代码 二级缓存的持久化类必须实现equals方法。; ^ U0 [+ @$ k* E7 b
: L; H# b4 y* `- _* C只有在SELECT时才会缓存。
5 t+ L4 e2 I/ i
2 e; ^7 d0 \3 v: ?$ a在同一个session里,查询2个不同的对象,会缓存2次,- Session sess=sf.openSession();
+ k- \9 x5 |8 k9 v' M* c - Book2 b=(Book2) sess.get(Book2.class, 17);
6 m$ K) p# h" M6 |( c - System.out.println(b);
& @" Z( _# _- j+ x - assertEquals("spring Recipes", b.getTitle());( k+ c; m' G6 i- E/ B
- Book2 b3=(Book2) sess.get(Book2.class, 18);
3 C5 u2 b" d: c8 ]. D+ K1 p% A$ B - assertEquals("dfad", b3.getTitle());, H9 `" M" }8 A8 k' z9 x# T
- sess.close();) b# t* V# d$ m. D0 T
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");& S M4 k- [! f5 \$ o4 V
- System.out.println(slcs);
复制代码 结果- SecondLevelCacheStatistics[hitCount=0,missCount=2,putCount=2,elementCountInMemory=2,elementC
0 S9 d1 z( q' N, W - ountOnDisk=0,sizeInMemory=3948]
复制代码 ( D8 K3 h' O; Q, T3 N( w
在同一个session里,查询相同的对象,会先查询一级缓存,一级缓存中有就不会查询二级缓存。- Session sess1=sf.openSession();
* N( a4 @# j. U9 Y- @+ ] - Book2 b1=(Book2) sess1.get(Book2.class, 17);
/ d, c: U2 h9 N: {" L4 K A) t4 l6 h - System.out.println(b);
' E6 V$ z: o; M4 f - Book2 b2=(Book2) sess1.get(Book2.class, 17);, z& Z& y% `3 `# n) ^5 ^8 s
- assertEquals("Spring Recipes", b1.getTitle());
2 r; y5 Y$ \+ R/ l3 A+ Z0 f - assertEquals("Spring Recipes", b2.getTitle());. {5 d) I3 r$ Y/ n7 j+ A
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");3 a$ l+ L# P6 n' _5 V9 [+ \
- System.out.println(slcs);
复制代码 结果,在新的session中,一级缓存不可用,就会使用二级缓存。- SecondLevelCacheStatistics[hitCount=1,missCount=2,putCount=2,elementCountInMemory=2,elementC
0 Y" A0 |3 a$ |5 Y/ q! ~ - ountOnDisk=0,sizeInMemory=3948]
复制代码 完整测试逻辑- @Test$ \9 J1 c8 z' F+ D1 F' l! r3 y g' N8 { w
- public void test2LCache()" N; W; { e9 C# v% {0 j" O
- {
/ B! P7 q- F0 i3 Y5 z4 h - Statistics stat=sf.getStatistics();//获取stat对象
- W" U- V1 k1 Z% E. i - Session sess=sf.openSession();
5 N! t2 |5 e# b7 N6 M" Y/ a* ]( n! [ - Transaction tx=sess.beginTransaction();
]( f% A& S: a3 m - $ ~! l- ]/ ~4 ]% ~1 v
- //存储对象,此时不会放到缓存中( G' O- v/ b4 }: r! k
- System.out.println("--------------存储对象---------------------------------");
( \$ D/ x5 j3 M( f - Book2 book=new Book2();
; ?$ H& e) Q' G! C - book.setTitle("Spring Recipes");
' X3 e0 G" a; A- g+ T1 ]. a5 d - sess.saveOrUpdate(book);
9 S# @' ~3 b( ? D$ A7 H - tx.commit();& F* x% d0 i, L ?9 w8 G
- sess.close();+ L* M! e) i3 [5 X2 t/ [
- System.out.println(book);4 Q* B, j8 `* x& Y
- SecondLevelCacheStatistics slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
% O l t H$ M6 x5 C - System.out.println(slcs);, ?/ _% C! s9 U7 Z8 W+ \/ Y9 v
- Cache cache=sf.getCache();
5 y6 E. m3 I3 U# P" Z - System.out.println(cache);
& |3 r: I4 n& {4 ~8 l4 x( O$ g0 e% m - cache.evictAllRegions();//从所有region中获取数据' F) N+ C+ \2 [! N
- Map map=slcs.getEntries();5 Z) `6 A9 G; q8 u$ [ l/ z
- System.out.println("Cache entries:"+map.size());
! W! z* X, l' H% L/ ?! k0 Z! v - System.out.println("--------------第一次查询后---------------------------------");
$ D% c$ V: L$ S7 j, a - sess=sf.openSession();; t, i7 F9 a9 s. N7 o
- tx=sess.beginTransaction();
' ~1 b6 E+ U+ G0 n5 @ - Book2 b1=(Book2) sess.byId(Book2.class).load(book.getId());//第一次查询
j8 w6 e6 p+ |( G2 X - System.out.println(b1);) F/ r( F. P B8 U4 Q0 V( `
- assertEquals(book, b1);( V, k& ?8 K+ u! z. m* v3 ^0 O
- tx.commit();4 `' U) n" g, t$ _2 z+ v
- sess.close();
% K' a1 L" c: J, N# F% M - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");7 K! Q% Z% f) R2 J# S9 H( |
- System.out.println(slcs);
2 I+ d+ \& z- o+ e - map=slcs.getEntries();( v; V l4 A& O" O8 {+ c8 _$ g9 j
- System.out.println(map.size());
$ s0 v& m" E) @6 _. Q- J - System.out.println("--------------第二次查询后---------------------------------");# l( T C4 S5 y! {
- sess=sf.openSession();
+ O- m; q. v4 g7 \5 w - tx=sess.beginTransaction();
8 x. r: {& E4 k' K. L! j - Book2 b2=(Book2) sess.byId(Book2.class).load(book.getId());//第二次查询
) G$ d; V2 B$ K* {% j5 d$ r - System.out.println(b2);
0 r- X- {% h: N3 W9 P5 T$ c - assertEquals(book, b2);
3 e1 J; l; |( ^6 }8 A6 w - tx.commit();, W; y& i3 q9 J* t Z) S% X1 a+ p
- sess.close();, `7 B/ u2 ]. B+ e0 t3 A5 \+ B
- 6 g& ]4 G2 O, n0 N2 \/ J* W) N
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
+ X9 Z3 H4 e' i - System.out.println(slcs);# H- `8 r9 z8 m$ u9 m6 Y6 }
- // this is the initial select' U) c; `& ^( j. z1 ^
- assertEquals(stat.getSecondLevelCacheMissCount(), 1);/ O! e0 S% {4 w7 Z. h: b
- // we put one element in the cache from the miss
4 R8 w) [ P; Z% ~# @ - assertEquals(stat.getSecondLevelCachePutCount(), 1);
' e# L g3 z5 \ ~: h - // we still didn't hit the cache, because of 1L cache
" o; j* t5 Y; e E% A - assertEquals(stat.getSecondLevelCacheHitCount(), 1);
- G) y! S8 ^8 R7 j - System.out.println("--------------第三次查询后---------------------------------");4 T5 W6 Z& j! x0 \7 h/ z
- sess=sf.openSession();
' A% i6 L) G" n" k0 J# u5 ^! A) S - tx=sess.beginTransaction();
% D6 k. Y( }* z7 B. d) x' f% ~3 } - b1=(Book2) sess.byId(Book2.class).load(book.getId());//第三次查询
- p( I- w5 W$ b3 p - assertEquals(book, b1);
/ r' J; f9 ]9 `! S& e - tx.commit();
! j& c4 M4 n; z. |. Q - sess.close();* X* B! e" {3 h# Q( z
-
b' k" i+ Y0 l/ X* }" P - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
& Q: Z9 T+ @! H: A M- i - System.out.println(slcs);; d0 S* }! R, `9 t0 E- |2 a
- // same miss count (we should hit now)
/ n; O2 Q6 |2 s) X$ d9 v - assertEquals(stat.getSecondLevelCacheMissCount(), 1);
+ r) ^/ w0 x2 Z2 u5 D - // same put count (we didn't put anything new)
6 n- j: Y- y" J2 { - assertEquals(stat.getSecondLevelCachePutCount(), 1);0 ?4 O3 m0 n3 ~9 l! \
- // now we hit the 2L cache for load1 N4 z/ T- J; O+ ^! R
- assertEquals(stat.getSecondLevelCacheHitCount(), 2);
5 H2 t: q0 ]" a% [" P5 C -
3 K0 U3 E+ x1 J - }
复制代码 完整测试结果- Hibernate: delete from book2
2 P+ Z I; r! `. l1 p, ] - --------------存储对象---------------------------------
3 D7 A( t& M2 M3 I q - Hibernate: insert into Book2 (title) values (?)/ I+ ?' } m+ u4 y
- com.xinglongjian.entity.hbm.Book2@521e083b- o- l3 p5 A- f$ v
- SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=0,elementCountInMemory=0,elementCountOnDisk=0,sizeInMemory=0]0 p/ ]! t. V; X: {$ K! J# r0 \" A" S
- org.hibernate.internal.CacheImpl@4830f6
5 f- t* q! }) |- M - Cache entries:0" t: A9 y% I+ s% @* y3 E: M
- --------------第一次查询后---------------------------------
- k" T+ h* y7 ~: P - Hibernate: select book2x0_.id as id1_0_0_, book2x0_.title as title2_0_0_ from Book2 book2x0_; V9 K5 l% I ?6 E+ s0 }0 y; c
- where book2x0_.id=?
@ X) J2 R* x6 j2 \4 R2 V - com.xinglongjian.entity.hbm.Book2@521e083b c# A) j2 l& a5 V
- SecondLevelCacheStatistics[hitCount=0,missCount=1,putCount=1,elementCountInMemory=1,elementC
* C# L# a& T$ S0 W8 [3 M3 p: T - ountOnDisk=0,sizeInMemory=1979]
* }7 ?) L* Y$ C+ k3 A - 1
: X- c" j% e& W: }2 ^ - --------------第二次查询后---------------------------------: Z. h, f! G& b0 d
- com.xinglongjian.entity.hbm.Book2@521e083b$ J9 p2 [7 e! t2 @! m
- SecondLevelCacheStatistics[hitCount=1,missCount=1,putCount=1,elementCountInMemory=1,elementC
" r, ]0 B+ s" f, [0 Q0 i - ountOnDisk=0,sizeInMemory=1979]1 } O8 D& Z8 z) Z/ S% x
- --------------第三次查询后---------------------------------
% C6 y6 P W n( Q3 l% J - SecondLevelCacheStatistics[hitCount=2,missCount=1,putCount=1,elementCountInMemory=1,elementC
+ ?' F& l* g8 w! T) r! L; t% Q - ountOnDisk=0,sizeInMemory=1979]
复制代码 ! F$ u0 y$ M# X% U6 r
|
|