该用户从未签到
|
需要启动二级缓存,二级缓存的scope是sessionFactory。也就是说二级缓存的数据可以在由相同SessionFactory创建的多个Session中重用。2 D1 C2 F* W; F1 G
- L& R& c) f1 s+ V0 m3 E5 ]7 }首先,要在hibernate.cfg.xml中设置一个cache Provider,hibernate支持多个cache实现,有EHCache,OSCache等。在非分布式环境中可以选择默认的EHCache。添加ehcahe jar7 K3 x: T* }+ [$ L
- <dependency>
# x! c c' D! b5 c - <groupId>org.hibernate</groupId>4 c/ W( i- e1 E/ Q9 C" i
- <artifactId>hibernate-ehcache</artifactId>0 E' a# b9 i1 ]6 [: B. R" S6 t* \" w
- <version>4.3.5.Final</version>) o" f$ g8 T ]. ~
- </dependency>
复制代码- <hibernate-configuration>
" U4 G1 q( D- g - <session-factory>, g( V% Q, Q/ o6 B: a/ N) Q
- <property name="connection.driver_class">com.mysql.jdbc.Driver</property>! D# Z) z# p; F" c* c! Z* W( M
- <property name="connection.url">jdbc:mysql://localhost/test</property>+ w2 S! _# A) k- W! c/ L: P' m
- <property name="connection.username">root</property>
) i- M% N. Q3 E e$ w; g9 P - <property name="connection.password"></property>
# G- |; \; K9 j' v0 }* x( M - <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
. C2 u. ?' @8 u) _- j - <property name="hibernate.show_sql">true</property>
: I0 P/ e* ?- q) G - <property name="hibernate.hbm2ddl.auto">update</property>
% O! O' M4 g% j4 G7 T - <property name="hibernate.generate_statistics">true</property>
4 F0 i: R+ a) T& m* T - <property name="hibernate.cache.region.factory_class">& m; O; r: X7 D& j8 `; D
- org.hibernate.cache.ehcache.EhCacheRegionFactory0 P& m2 q, ]1 o# t: ]4 A! u
- </property># c6 W, s& Z6 r) R' |
- <mapping class="com.xinglongjian.entity.hbm.Book2"/>2 e# W. Z+ U& A) o( }' N6 @# B
- </hibernate-configuration>
复制代码 1 _3 z( U0 z8 T: z L- U
第二,通过ehcache.xml配置EHCache,该文件放置于classpath的根目录下。可以在该配置文件中设置将不同的对象存储在不同的regions。- <ehcache>
- A! ^9 \! Y; c* {% d/ w - <diskStore path="c:/data/ehcache"/>
5 h1 b" L. f# ^ - <defaultCache2 ]' x* b1 `; W. Y8 N8 V- u C' c
- maxElementsInMemory="10"0 [& \# a( P+ Y4 D+ K5 b7 N
- eternal="false"# _8 f/ w G' P) ?) t
- overflowToDisk="true"
' d8 X$ U' F+ B4 a) m. x0 N+ j9 `6 C - timeToIdleSeconds="120"
2 d4 A6 i& ~8 r, [( z - timeToLiveSeconds="120") W* m4 e9 ^6 `4 [0 m) u5 j
- diskPersistent="false"5 G- @/ G' k ~4 c: B; s& Q3 u! Z
- diskExpiryThreadIntervalSeconds="120"/>5 R1 q, K# t' `5 @5 T+ N' S
- <cache name="com.xinglongjian.entity.hbm.Book" maxElementsInMemory="10" eternal="false" 7 M/ F& {$ i3 d& ~: i1 ?. N; w
- overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false"/>6 Y) [2 ^; T" x. p
- </ehcache>
复制代码 第三,设置持久化类- @Entity
) i, |. h+ L$ \: z - @Cacheable c; z$ ^$ N/ j l1 a+ h4 Y+ `7 e7 y
- @Cache(usage=CacheConcurrencyStrategy.READ_ONLY,region="com.xinglongjian.entity.hbm.Book")
9 Y% s3 H! ^0 z* ^ - public class Book2 {
0 i9 A/ d6 }0 u- M9 s$ A - @Id( n1 T! U; f8 q$ G
- @GeneratedValue
( `8 c+ J1 w6 q0 X7 v5 o - private int id;1 e% @$ |% h! _' r: K
- private String title;) Y: j5 D9 i, F7 B9 A1 \
- public String getTitle() {5 s0 Z2 Q$ Y( R" N4 M
- return title;
" o! ^. f# R9 T: J( D/ \( w - }
3 L* R. ~% S2 D; R+ m - public void setTitle(String title) {/ Q, H, P9 F0 P# W1 k# O2 q
- this.title = title;2 S, Q( w1 O' @$ Z2 z
- }* F* L3 b4 B; R+ u4 ^! X& c/ @
- public int getId() {
( d4 N5 O( k2 e - return id;
\! f; J* G! i0 j" V- J - }5 P: I# a0 ^ e8 `
- public void setId(int id) {
; z' i) ~5 s( m/ F4 n, n: P - this.id = id;4 f$ K& u9 k. X- T0 M/ {+ d: G
- }
4 M/ u& m' P, x6 d2 y5 \" p1 _/ t - @Override! R. d# e$ a; ?& u4 X: |' ]) R8 N
- public int hashCode() {& h- C0 k8 f% U$ ~
- final int prime = 31;
3 K. Z' e/ U; {9 r - int result = 1;
& X& B" u' R( D; t! y# z9 S% { - result = prime * result + id;5 D5 l; p7 v {
- result = prime * result + ((title == null) ? 0 : title.hashCode());
3 Q" Y& ?- W9 e - return result;- U h7 e" [6 l
- }
! o; T" y- w4 t1 R1 r3 ? - @Override' \8 e# d! W& u' ]9 t$ ^- I4 g
- public boolean equals(Object obj) {6 x: Z3 \6 }( V9 s5 e8 l- f
- if (this == obj)
% }- f7 f8 }9 G+ X6 M - return true;
& V- ]2 ?3 X) s- E$ Q* R0 q - if (obj == null)- A; \( D0 Z' S/ {
- return false;
' R u' Z5 x& b& I; W- V% z+ | - if (getClass() != obj.getClass())% n6 U" R' |5 J
- return false;7 G3 @; P- L+ E: D8 c2 c6 l
- Book2 other = (Book2) obj;6 L' Z0 j+ z( y4 k. A* l! k2 E
- if (id != other.id)# G) I" Z1 ]4 T8 e R9 w( T
- return false;
: Z- z. ~: ^) c3 M7 C - if (title == null) {( ?9 v9 j8 ~) l) B8 _% [
- if (other.title != null)
( J& ?6 j. H+ q3 t4 w - return false;
" Y% Q$ ?' r* z, `3 i2 ]& c - } else if (!title.equals(other.title))
' h* k+ O2 w, s/ q2 `* h6 V2 S/ D5 T - return false;( A2 l. }/ [: ?
- return true;
) O; S" m$ |! w+ M u - }
& C5 }( V$ n' W; l0 p5 A5 d$ h -
* u3 }2 k% o/ R- a. N; a$ e - }
复制代码 二级缓存的持久化类必须实现equals方法。
2 i3 Z( Z' r: X7 I) I2 m8 r i U% a* E- d
只有在SELECT时才会缓存。
9 z& S! H- N- [6 O* P, k/ {6 O$ q
在同一个session里,查询2个不同的对象,会缓存2次,- Session sess=sf.openSession();
7 K2 e9 C# P* C- b: Z - Book2 b=(Book2) sess.get(Book2.class, 17);
- R& c* d6 P E6 C' F. C# n) B# @- \ - System.out.println(b);* a# G3 ~2 c( x Q3 r
- assertEquals("spring Recipes", b.getTitle());$ F% P- \. h: R6 B; y: d. t8 ?
- Book2 b3=(Book2) sess.get(Book2.class, 18);
: p! S' M& ?9 M: m - assertEquals("dfad", b3.getTitle());
) c4 e% k7 }' r, M0 K - sess.close();5 w7 W0 s; c2 @% E6 y
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
. |7 I1 P! K; Z( U - System.out.println(slcs);
复制代码 结果- SecondLevelCacheStatistics[hitCount=0,missCount=2,putCount=2,elementCountInMemory=2,elementC
4 c V X6 t, G8 I; V7 o8 F - ountOnDisk=0,sizeInMemory=3948]
复制代码 2 e# g+ g/ o2 v8 Q0 m; S
在同一个session里,查询相同的对象,会先查询一级缓存,一级缓存中有就不会查询二级缓存。- Session sess1=sf.openSession();
u5 E" s0 s/ }- }; @1 Z, t - Book2 b1=(Book2) sess1.get(Book2.class, 17);& }" a0 p# q3 Q5 y: i# A& v: r! }' p
- System.out.println(b);
* n3 `! Y, K3 ~1 T0 N5 E! K - Book2 b2=(Book2) sess1.get(Book2.class, 17);! C- ^& R8 E& X: S4 l
- assertEquals("Spring Recipes", b1.getTitle());9 ?2 ~9 l7 C2 K+ |9 C0 Q
- assertEquals("Spring Recipes", b2.getTitle());* a4 H- }! y; h, ?$ R! n V
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");) V3 m7 R: q. F& C7 d
- System.out.println(slcs);
复制代码 结果,在新的session中,一级缓存不可用,就会使用二级缓存。- SecondLevelCacheStatistics[hitCount=1,missCount=2,putCount=2,elementCountInMemory=2,elementC( o* \ D i/ b
- ountOnDisk=0,sizeInMemory=3948]
复制代码 完整测试逻辑- @Test, |& v) x" ^# b ]' s9 Z
- public void test2LCache()
2 w# X! k6 ^+ h - {
* k7 ?% y4 r3 @( T8 C+ f7 m - Statistics stat=sf.getStatistics();//获取stat对象. f+ h A+ D' M
- Session sess=sf.openSession();
; k8 Z" X% I/ f4 E* y, \ - Transaction tx=sess.beginTransaction();
: \1 ^' j; d. ]0 S - : E* e' r7 M: K1 [7 K- n
- //存储对象,此时不会放到缓存中0 ^/ }$ W0 v1 F* ?0 f9 \) T
- System.out.println("--------------存储对象---------------------------------");
% ?# q) F$ F1 y! b# S4 z P t9 ` - Book2 book=new Book2();& u6 I* o5 Z3 i/ ^: y* D
- book.setTitle("Spring Recipes");6 R/ P$ F0 [. \1 h4 ?6 n
- sess.saveOrUpdate(book);
, j$ I: R4 X4 n8 p - tx.commit();8 i% r2 i& [% m E* M1 b8 K
- sess.close();5 Q M2 `* H0 m# X$ x9 k4 x
- System.out.println(book);. l; z) j% g' F. f" j$ ]4 K7 S( U
- SecondLevelCacheStatistics slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
# `9 d7 j; S ~, [) H( j - System.out.println(slcs);5 `1 Y$ x# g* K) |% b
- Cache cache=sf.getCache();
8 _( p9 X! x3 E. b3 W, G - System.out.println(cache);. D' i" i# U7 e3 a6 j+ \! F
- cache.evictAllRegions();//从所有region中获取数据3 A: r. Q. ?' Y H5 k
- Map map=slcs.getEntries();
5 e4 a4 e. d% m7 s3 R* M - System.out.println("Cache entries:"+map.size());8 _) x a+ o6 t
- System.out.println("--------------第一次查询后---------------------------------");7 t8 e' [) ]7 t+ D; X
- sess=sf.openSession();
% S4 G; l4 k3 [$ j7 S - tx=sess.beginTransaction();$ B6 l- z- C1 ?6 q
- Book2 b1=(Book2) sess.byId(Book2.class).load(book.getId());//第一次查询+ v! V9 v9 Y# B$ k/ A. [0 Z
- System.out.println(b1);% E! U2 {- Y ^: \2 J* g+ {' f" _
- assertEquals(book, b1); B: B. X6 r! X
- tx.commit();
/ y* i. O/ i) S - sess.close();
* e8 A/ |4 x* _4 }) G - slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");$ g! K t4 u9 s
- System.out.println(slcs);
# [+ o) j3 i f1 Q' c' Z - map=slcs.getEntries();& Q. i4 T' {5 z# a# a# l) l' A5 ]+ N
- System.out.println(map.size());
9 f. z `! _( Y# c, q9 ~ - System.out.println("--------------第二次查询后---------------------------------");, \8 l4 i2 `. j
- sess=sf.openSession();; D7 l3 i$ Y8 T' W2 O
- tx=sess.beginTransaction();5 W! k: n: b2 ]) y- l# F
- Book2 b2=(Book2) sess.byId(Book2.class).load(book.getId());//第二次查询
2 ~1 ~( ], R* q. h% H9 I1 O - System.out.println(b2);
1 M3 R/ j9 ~8 H4 r( | - assertEquals(book, b2);6 M) E: y B8 o5 F3 |3 H
- tx.commit();
+ A4 [1 X# K) @- h' _& t( y4 E - sess.close();, s2 `5 N8 s7 O$ ?% n, c
- 1 q" |: ^& X f' a5 @( L
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
$ k9 F* {9 q8 |# W+ ] - System.out.println(slcs);1 N% d3 c& d# L# l
- // this is the initial select( [! b }) }- J( o
- assertEquals(stat.getSecondLevelCacheMissCount(), 1);0 }7 P" m3 @$ I
- // we put one element in the cache from the miss6 h8 }; X. j! l8 [$ z
- assertEquals(stat.getSecondLevelCachePutCount(), 1);! H- A3 g2 R; E2 Z
- // we still didn't hit the cache, because of 1L cache
4 m$ K; H4 Z; M: @+ i: K - assertEquals(stat.getSecondLevelCacheHitCount(), 1);
1 i5 e" E! l1 d5 y - System.out.println("--------------第三次查询后---------------------------------");
! P7 d* O8 r. r( {) t% ` - sess=sf.openSession(); x$ Y; {3 h' }' S! m# P+ ]
- tx=sess.beginTransaction();
+ S6 Q$ T0 o. Y* g0 M5 W - b1=(Book2) sess.byId(Book2.class).load(book.getId());//第三次查询
% P/ n: u. K/ i t q - assertEquals(book, b1);( F7 ]# w: s! t2 L
- tx.commit();
" t6 d: c. g: W2 }; @9 s h6 X - sess.close();1 }( s" h9 f/ m3 V* [& z/ @# D
- 4 m% }* ]1 A$ u8 g/ s: J) P
- slcs=stat.getSecondLevelCacheStatistics("com.xinglongjian.entity.hbm.Book");
. ]$ M5 `1 N4 r0 D9 Q+ L. C1 F3 m& T - System.out.println(slcs);
) A# x0 B( P( [ - // same miss count (we should hit now)
3 ?, Q8 a7 \) N5 t8 Y% D" D" t - assertEquals(stat.getSecondLevelCacheMissCount(), 1);
4 @9 t1 L: w5 v2 \0 ^) [. x - // same put count (we didn't put anything new)4 D4 S& h$ `% Q# ^% J
- assertEquals(stat.getSecondLevelCachePutCount(), 1);
+ g- R+ x. k) U# ] - // now we hit the 2L cache for load
* y5 o) M& g& U7 b D+ S - assertEquals(stat.getSecondLevelCacheHitCount(), 2);
: j _/ |6 [4 W - 9 |! W; c& d5 c
- }
复制代码 完整测试结果- Hibernate: delete from book2
# P; L! `6 H% ~8 q) o) {; Y5 Q - --------------存储对象---------------------------------
, r. d7 j& U; A5 n$ R) f - Hibernate: insert into Book2 (title) values (?)" T8 C( i! g5 P; p9 B
- com.xinglongjian.entity.hbm.Book2@521e083b; g5 h1 p5 t1 |8 K- }
- SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=0,elementCountInMemory=0,elementCountOnDisk=0,sizeInMemory=0]
3 X0 s: Z( n% l - org.hibernate.internal.CacheImpl@4830f6; f3 l8 ]0 T: E) [1 I' u4 p
- Cache entries:0
. a& L% m8 E" y. k5 h2 n' \# Q+ ^ - --------------第一次查询后---------------------------------
+ \) X3 k# I U - Hibernate: select book2x0_.id as id1_0_0_, book2x0_.title as title2_0_0_ from Book2 book2x0_. p6 e( D( R: b" P- c
- where book2x0_.id=?0 T6 o z F1 s
- com.xinglongjian.entity.hbm.Book2@521e083b
* P2 c& |2 n! L0 K3 u' Y( L! z1 ~ - SecondLevelCacheStatistics[hitCount=0,missCount=1,putCount=1,elementCountInMemory=1,elementC
6 | n8 X1 Y5 r: k - ountOnDisk=0,sizeInMemory=1979]
' k: b5 [; r$ x0 l0 ^. T- t - 1
* i4 p& S$ J! Q' R: B Q: Z - --------------第二次查询后---------------------------------
- n* T3 g j: u9 Y9 E5 O - com.xinglongjian.entity.hbm.Book2@521e083b
( F, z5 j6 Z/ D4 I6 j. R4 K - SecondLevelCacheStatistics[hitCount=1,missCount=1,putCount=1,elementCountInMemory=1,elementC
* g6 Z: k! a* k - ountOnDisk=0,sizeInMemory=1979]
3 a1 l4 f% H5 @: l! n5 M - --------------第三次查询后---------------------------------- X; J& o9 G' K" t4 O$ H- H5 F/ j
- SecondLevelCacheStatistics[hitCount=2,missCount=1,putCount=1,elementCountInMemory=1,elementC
6 \" B( E8 x* j c* T" V - ountOnDisk=0,sizeInMemory=1979]
复制代码 # ]' {, B( j8 L. @
|
|