该用户从未签到
|
需要启动二级缓存,二级缓存的scope是sessionFactory。也就是说二级缓存的数据可以在由相同SessionFactory创建的多个Session中重用。
: \( _% S" `0 R4 W/ E2 A& t( j& W! [) f
首先,要在hibernate.cfg.xml中设置一个cache Provider,hibernate支持多个cache实现,有EHCache,OSCache等。在非分布式环境中可以选择默认的EHCache。添加ehcahe jar7 w) X4 V) N+ B, }
- <dependency>/ }& x" ^- f- }
- <groupId>org.hibernate</groupId>
( W1 T) p6 K1 U* f - <artifactId>hibernate-ehcache</artifactId>$ v: e2 R4 i0 W0 N4 h8 \" `, U
- <version>4.3.5.Final</version>
" e( `2 T# t$ I5 q y/ Y# S4 x9 M - </dependency>
复制代码- <hibernate-configuration> X! c% S7 \5 Z, V6 e4 @
- <session-factory>! e; B* e7 G% O7 i4 G; o
- <property name="connection.driver_class">com.mysql.jdbc.Driver</property>2 W( T) a6 O B5 ?
- <property name="connection.url">jdbc:mysql://localhost/test</property>) f3 {+ u I9 Y: [/ k( ^: r2 A
- <property name="connection.username">root</property>
# r* z+ W$ \9 K% O - <property name="connection.password"></property>" j) ^4 Q- T4 Q; i
- <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property># j* C" H6 h; P# Z
- <property name="hibernate.show_sql">true</property>
8 q& U. E# y2 Q; S9 l/ D9 N/ B - <property name="hibernate.hbm2ddl.auto">update</property>8 \1 F# y) M( O* v& a
- <property name="hibernate.generate_statistics">true</property> p) y0 d1 I& |" A
- <property name="hibernate.cache.region.factory_class">
; V; c) _& z; t; s) F7 { - org.hibernate.cache.ehcache.EhCacheRegionFactory" H7 d: P7 O# O/ z0 F2 n
- </property>- D1 F$ n6 h* v4 ^
- <mapping class="com.xinglongjian.entity.hbm.Book2"/>
: }# C0 e0 k7 g# v' |- _+ Z, [ - </hibernate-configuration>
复制代码
% Z8 G# ?; z; n: _. ^( H8 b6 t' Y 第二,通过ehcache.xml配置EHCache,该文件放置于classpath的根目录下。可以在该配置文件中设置将不同的对象存储在不同的regions。- <ehcache>& |2 a2 c3 I# c0 x* D- `" J! K* Y8 j
- <diskStore path="c:/data/ehcache"/># e6 G9 Z6 M7 I/ B/ [6 c2 g
- <defaultCache: G% n7 [; Z& a) R/ `4 }+ z
- maxElementsInMemory="10"
4 f$ S& @: y- z. L1 V) q, H - eternal="false"
: S& @, ~. B1 C9 ?% k$ u - overflowToDisk="true"
! _$ I& K" u& O+ D - timeToIdleSeconds="120"- m, p5 c) s, G; c+ I5 W0 l
- timeToLiveSeconds="120"; r2 R# J% i; O$ A- s8 d1 e
- diskPersistent="false"
% o8 \8 E2 F8 o0 B, o - diskExpiryThreadIntervalSeconds="120"/>
6 T; k- f- {8 x) n - <cache name="com.xinglongjian.entity.hbm.Book" maxElementsInMemory="10" eternal="false"
0 n# e" J$ L( A - overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false"/>
" i4 |$ `) [2 q3 V5 f/ E( L% _ - </ehcache>
复制代码 第三,设置持久化类- @Entity
5 v8 D! P3 Z2 w1 }( }! H" U - @Cacheable
( j5 \/ O2 l- g - @Cache(usage=CacheConcurrencyStrategy.READ_ONLY,region="com.xinglongjian.entity.hbm.Book")# S/ K s' Y! _# a
- public class Book2 {# r: |% a+ U7 p" I3 D! q
- @Id
& a5 S' X/ w8 n - @GeneratedValue! A0 E* T N( E( L' s5 }! c
- private int id;
z3 o" I0 B9 b# { - private String title;
8 n' h, J7 I4 n& K5 h! s - public String getTitle() {
8 r9 ?. d- X; U9 n - return title;3 |) \4 g* _" `& O- m- h
- }
& O) G2 f9 L5 D5 L2 o% Y - public void setTitle(String title) {1 A M% v, W: T: g0 j
- this.title = title;
/ s' f; M( r6 |5 s9 E* u Z6 A - }- l8 [0 L# f6 ^, }
- public int getId() {% I8 o, X" J- i2 d& S! Q7 ^5 E
- return id;8 }1 p: G* i* B6 t
- }
5 x7 x' ]+ T3 ?) @; s3 F) ~ - public void setId(int id) {
: x* s+ c2 C5 z: N! R' t) S, ] - this.id = id;
3 Z7 F; O0 H/ K - }
7 f9 y. p8 `( M! ? - @Override
; N( V- n% I7 K - public int hashCode() {" x3 w B( c- w2 N: u3 J) x* N
- final int prime = 31;7 L6 j: C& F3 L
- int result = 1;
* B" |$ @3 p" o; r/ A( G9 y" F# O - result = prime * result + id;
2 h' j U& b2 [; Z# X: Q - result = prime * result + ((title == null) ? 0 : title.hashCode());9 E5 y( ~3 f/ y2 j* y% h
- return result;
+ h( A1 }$ c( p# c9 K" ~9 Z! b - }" } |* }- s1 z" q. f
- @Override8 `4 [' s; E @' _" e$ |
- public boolean equals(Object obj) {8 I( \- n! S( ]
- if (this == obj)
% y( f( X5 S* X9 p6 u" o8 V - return true;
" }' V, Y ~. J - if (obj == null)
( M6 e' i! w9 J$ p - return false;
5 B d7 [. e0 N2 g/ H& H" a - if (getClass() != obj.getClass())2 j% c; {* `( d
- return false;
+ a4 U. j9 k8 K1 Q. I - Book2 other = (Book2) obj;
$ [! z% n8 E* j' h1 M& h1 Q0 v5 j' P - if (id != other.id)8 u. J3 p- S4 d# k3 ~/ W2 K: m+ Q
- return false;
5 l& v* x; \3 h5 t2 e: t/ e k - if (title == null) {. P. G* C1 q7 O: f* e1 c. p
- if (other.title != null)6 w' `+ J$ ?* x, k X' H0 n
- return false;6 f9 s0 P2 v9 ]& W3 Y
- } else if (!title.equals(other.title))
y0 _, L. N3 y1 H M - return false;
8 M# _3 @# h. k - return true;& O3 X1 C: h; R
- }( K7 W x, D- h* w
-
1 p8 ^5 g+ H& _( g4 }& } - }
复制代码 二级缓存的持久化类必须实现equals方法。; r2 t1 U7 Z* E* d
4 m; M9 ?. c$ u- S0 c Q
只有在SELECT时才会缓存。: T3 m+ N; q [2 w3 P) E5 C
# G3 d, L; K8 B X在同一个session里,查询2个不同的对象,会缓存2次,- Session sess=sf.openSession();
. l. G; a7 L, ~% t& }7 Q8 E( h - Book2 b=(Book2) sess.get(Book2.class, 17);2 w' G: @. e& |, S$ ^# ?
- System.out.println(b); Q! O3 B/ G2 m, o0 R) x
- assertEquals("spring Recipes", b.getTitle());, l6 c6 j; [! W* d4 y
- Book2 b3=(Book2) sess.get(Book2.class, 18);
, k/ {$ v( y3 K, {- s" X - assertEquals("dfad", b3.getTitle());
! H: h) y, j7 H# ^ - sess.close();
# H9 Q3 p. q: X1 y* ^0 p' b - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");" o# g8 M) I" j" c
- System.out.println(slcs);
复制代码 结果- SecondLevelCacheStatistics[hitCount=0,missCount=2,putCount=2,elementCountInMemory=2,elementC) F2 q, m# j! I5 n# N; I: T
- ountOnDisk=0,sizeInMemory=3948]
复制代码
( }4 \/ S8 u7 o' A" d' U 在同一个session里,查询相同的对象,会先查询一级缓存,一级缓存中有就不会查询二级缓存。- Session sess1=sf.openSession();5 i# r5 Q3 W" a0 X% u2 X6 s
- Book2 b1=(Book2) sess1.get(Book2.class, 17);
; p" r$ X& e4 | - System.out.println(b);
9 K# t- C t# A' ?5 ` s- i: k' C - Book2 b2=(Book2) sess1.get(Book2.class, 17);7 y( L/ x5 M) Q- ^) D2 l" n
- assertEquals("Spring Recipes", b1.getTitle());
. R: B! r' r' C+ n" A - assertEquals("Spring Recipes", b2.getTitle());
8 A" h$ m9 q; d/ w0 L: e' B8 Z- z% l - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");3 x8 ^" H! U1 f" h1 \
- System.out.println(slcs);
复制代码 结果,在新的session中,一级缓存不可用,就会使用二级缓存。- SecondLevelCacheStatistics[hitCount=1,missCount=2,putCount=2,elementCountInMemory=2,elementC
% B& b, n* b; v' ]' J - ountOnDisk=0,sizeInMemory=3948]
复制代码 完整测试逻辑- @Test
! h- j6 E3 P5 W* J+ L' Q - public void test2LCache()
3 J! g- y* ?9 f+ ]1 _ i; O - {/ {: R6 x( O7 H' ]
- Statistics stat=sf.getStatistics();//获取stat对象7 E: h" G) M; u. c
- Session sess=sf.openSession();2 ?# u X; d4 A* [7 [
- Transaction tx=sess.beginTransaction();, _7 u' \' ^- I
- 8 ]; L- @/ X0 K" w" X! D
- //存储对象,此时不会放到缓存中+ v9 w" b4 P8 j
- System.out.println("--------------存储对象---------------------------------");/ {2 x- _4 V0 o. A
- Book2 book=new Book2();
. U0 H9 w3 r* I) g+ H - book.setTitle("Spring Recipes");- U7 b5 z# W& `6 n! [0 ?: {8 G
- sess.saveOrUpdate(book);
\4 @- Q- F% L2 z9 l6 o - tx.commit();
6 A5 F/ _8 r e+ I - sess.close();
7 I2 ^/ d% `% @. Z0 [* R6 d a( L - System.out.println(book);
5 S( J- _5 d* L7 j5 Z - SecondLevelCacheStatistics slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
- {* t7 B% ]4 p* [( \* w! x - System.out.println(slcs);
/ j0 W J$ ` s9 T& ? - Cache cache=sf.getCache();5 a. ?: v# a- P9 b6 ]0 t" s% A
- System.out.println(cache);# }& X$ W+ C4 ?+ W3 F* g5 n8 F
- cache.evictAllRegions();//从所有region中获取数据
g5 v2 g0 ?3 Y; l, \ - Map map=slcs.getEntries();
5 O, J6 ~8 U( I: K - System.out.println("Cache entries:"+map.size());
4 {" H% b2 E" y9 i& I" }9 U - System.out.println("--------------第一次查询后---------------------------------");
: ^" V! j1 }0 t, y - sess=sf.openSession();' _5 p$ E5 K" b# C
- tx=sess.beginTransaction();( W6 u Y( A4 M: b# D' N5 \
- Book2 b1=(Book2) sess.byId(Book2.class).load(book.getId());//第一次查询
& d7 l# ~/ Y; A4 M# D! M - System.out.println(b1);
/ W" ]9 C4 A4 h - assertEquals(book, b1);( u, b* [0 A4 n1 i6 f ^
- tx.commit();
: m" e8 _; z8 ^3 ?* l. o - sess.close();% J3 t% L: o. t& l+ I4 ^
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");( ?( q8 H. b% \" w
- System.out.println(slcs);2 Y: T6 U8 z- s9 o3 Z. e# E
- map=slcs.getEntries();
2 k/ ^' W0 ~; Z7 {: M - System.out.println(map.size());, L: a! P* d1 C8 a* z% L' b
- System.out.println("--------------第二次查询后---------------------------------");
" i8 x. Q( `% ~- V7 {, R. ?5 a* ` - sess=sf.openSession();( r/ l y3 ]5 B; R3 W% ^
- tx=sess.beginTransaction();
4 H! g( [8 A% ?/ |# V4 s* \- H - Book2 b2=(Book2) sess.byId(Book2.class).load(book.getId());//第二次查询( v* F0 M5 {3 G! z
- System.out.println(b2);
& z7 m+ Z+ V: n - assertEquals(book, b2);8 p [. j9 f" n6 Z: T
- tx.commit();
) z6 ?6 v4 A1 l4 d1 m - sess.close();8 r: V1 F" K8 l* ^
-
* W) Q7 K3 B8 s/ _/ g - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
L2 b. ?- ]2 q$ q - System.out.println(slcs);" B2 b/ I$ B/ s' Z8 F2 u: ?3 E" I
- // this is the initial select
- }' o3 u* A9 I4 N6 k1 w1 |' f - assertEquals(stat.getSecondLevelCacheMissCount(), 1);
4 e* y; |7 `& O. p2 q3 d - // we put one element in the cache from the miss
- G8 ^% K4 L9 E - assertEquals(stat.getSecondLevelCachePutCount(), 1);/ V' v$ i: |& R) J3 h
- // we still didn't hit the cache, because of 1L cache
* k0 P3 R6 ]7 G+ q$ ^3 l - assertEquals(stat.getSecondLevelCacheHitCount(), 1);
8 E$ {7 r0 F& h3 F - System.out.println("--------------第三次查询后---------------------------------");, M7 d$ D m( D8 u
- sess=sf.openSession();7 {6 a+ g! [% `- g
- tx=sess.beginTransaction(); Y* I3 R# w, C$ {. ?/ ` `# E6 ^+ U
- b1=(Book2) sess.byId(Book2.class).load(book.getId());//第三次查询
* U" {5 T0 R6 G: J0 L - assertEquals(book, b1);* [; U: y S0 H
- tx.commit();
% z6 }' Z/ q8 Y: z1 g" e: [; V. u - sess.close();
9 x1 k5 n; [3 q1 n. F7 @' T -
5 u# {9 a% G) D - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
* [7 V! d( F9 Z4 k - System.out.println(slcs);
0 n. T+ f/ [1 _8 a/ V - // same miss count (we should hit now)
3 m$ k) v P* [ - assertEquals(stat.getSecondLevelCacheMissCount(), 1);/ O& L6 Q$ ^4 _( x
- // same put count (we didn't put anything new)* h; N; j0 O P7 A
- assertEquals(stat.getSecondLevelCachePutCount(), 1);
9 j* Z) E; n. d& f# h9 H - // now we hit the 2L cache for load9 J; {% d# X! d3 c, O& Q
- assertEquals(stat.getSecondLevelCacheHitCount(), 2);
: Q' }5 f8 @$ t2 {$ L; A# E' L6 G% s - 9 a z4 }; D; k
- }
复制代码 完整测试结果- Hibernate: delete from book2
; \' ~, h7 t3 K9 ?- T. w: V - --------------存储对象---------------------------------( t3 O$ Z4 B% M* Z4 I
- Hibernate: insert into Book2 (title) values (?)7 w5 [6 O: R$ z/ X& Q' i
- com.xinglongjian.entity.hbm.Book2@521e083b
, _' [* X1 Q$ E9 n/ y. c - SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=0,elementCountInMemory=0,elementCountOnDisk=0,sizeInMemory=0]
1 E! ~; ?* Z2 x' ^1 J! {0 p1 g - org.hibernate.internal.CacheImpl@4830f6
0 ?$ U- ?( b4 g0 ] - Cache entries:0
& a3 Q) q& h( K* v0 p - --------------第一次查询后---------------------------------8 h: f2 s x5 x0 G
- Hibernate: select book2x0_.id as id1_0_0_, book2x0_.title as title2_0_0_ from Book2 book2x0_% L) s- \% m( M* ^$ D. u
- where book2x0_.id=?9 X9 D- Y4 q8 @& _1 }2 C
- com.xinglongjian.entity.hbm.Book2@521e083b$ i" Y" l, I) x) [. }
- SecondLevelCacheStatistics[hitCount=0,missCount=1,putCount=1,elementCountInMemory=1,elementC
; I( p8 y9 r0 z* @' H+ T) Y - ountOnDisk=0,sizeInMemory=1979]
! j( u) X+ j' F$ p. g [1 d) g - 1
2 y' z3 g8 o2 {: {- U) `3 M. J9 t& b - --------------第二次查询后---------------------------------' k$ c7 g9 ^4 Z
- com.xinglongjian.entity.hbm.Book2@521e083b
5 ^! B# k6 [6 A. H- b5 R - SecondLevelCacheStatistics[hitCount=1,missCount=1,putCount=1,elementCountInMemory=1,elementC
+ x& s, [' m$ }2 M - ountOnDisk=0,sizeInMemory=1979]9 P1 U3 k7 b' g) r% c
- --------------第三次查询后---------------------------------
# ^% C' Z! p8 O. m/ P - SecondLevelCacheStatistics[hitCount=2,missCount=1,putCount=1,elementCountInMemory=1,elementC+ K: H) }: O5 E
- ountOnDisk=0,sizeInMemory=1979]
复制代码
4 i+ W5 G* j- |3 A |
|