在《Spring使用内存数据库》和《Spring使用内存数据库二》中我们介绍了spring使用内存数据库和JPA进行持久化操作,使用ORM进行持久化操作经常会使用的一个设计概念就是缓存,本文将简单介绍JPA+Hibernate+Ehcache的配置和实现来延伸上两个demo的实现;EclipseLink自带有二级缓存实现而且号称很强大,大家可以试试,当然结合Oracle Coherence就更强大了;OpenJPA号称也很强大,特别是得到IBM的支持后在Websphere应用服务器的实现更强大了,不过不管是Websphere还是TopLink/Coherence都是商业企业产品,都很笨重而且需要Money,还是开源的Better。
首先,配置更新:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public
Map<String, Object> jpaProperties() {
Map<String, Object> props =
new
HashMap<String, Object>();
//Hibernate JPA properties
props.put(
"hibernate.dialect"
, H2Dialect.
class
.getName());
//以下两行指示使用二级缓存
props.put(
"hibernate.cache.use_second_level_cache"
,
"true"
);
props.put(
"hibernate.cache.use_query_cache"
,
"true"
);
//显示统计数据,这样我们通过输出结果就可以知道缓存命中情况等
props.put(
"hibernate.generate_statistics"
,
"true"
);
//本文使用Hibernate4,对于以前的版本可以使用如***释代码
//props.put("hibernate.cache.provider_class", org.hibernate.cache.EhCacheProvider.class.getName());
props.put(
"hibernate.cache.region.factory_class"
, EhCacheRegionFactory.
class
.getName());
return
props;
}
|
其次,在实体类Order和Item中增加缓存标注:
1
2
3
4
5
6
7
8
9
10
|
@Entity
@Cacheable
@Cache
(region=
"orders"
, usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table
(name=
"T_ORDER"
)
public
class
Order {
//---------------------------------------------
@Entity
@Cacheable
@Cache
(region=
"items"
, usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public
class
Item {
|
然后,增加ehcache配置文件ehcache.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
ehcache
>
<
defaultCache
maxElementsInMemory
=
"10000"
eternal
=
"false"
timeToIdleSeconds
=
"86400"
timeToLiveSeconds
=
"86400"
overflowToDisk
=
"false"
clearOnFlush
=
"true"
statistics
=
"false"
memoryStoreEvictionPolicy
=
"LRU"
>
</
defaultCache
>
<!-- 单独对某个entity的缓存策略设置 -->
<
cache
name
=
"orders"
maxElementsInMemory
=
"10000"
eternal
=
"false"
timeToIdleSeconds
=
"86400"
timeToLiveSeconds
=
"86400"
memoryStoreEvictionPolicy
=
"LFU"
transactionalMode
=
"off"
>
</
cache
>
<
cache
name
=
"items"
maxElementsInMemory
=
"10000"
eternal
=
"false"
timeToIdleSeconds
=
"86400"
timeToLiveSeconds
=
"86400"
memoryStoreEvictionPolicy
=
"LFU"
transactionalMode
=
"off"
>
</
cache
>
</
ehcache
>
|
最后,修改单元测试用例和Maven依赖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
public
void
testSaveAndFind()
throws
Exception {
for
(
int
i=
0
; i<
1000
; i++){
Order order =
new
Order();
Item item =
new
Item();
item.setProduct(
"foo"
+i);
order.getItems().add(item);
entityManager.persist(order);
}
entityManager.flush();
// Otherwise the query returns the existing order (and we didn't set the
// parent in the item)...
entityManager.clear();
Query query2 = entityManager
.createQuery(
"select o from Order o join o.items i "
);
//query2.setHint("org.hibernate.cacheable", true);
if
(query2
instanceof
QueryImpl){
((QueryImpl)query2).getHibernateQuery().setCacheable(
true
);
}
assertEquals(
1000
, query2.getResultList().size());
query2.getResultList();
Query query = entityManager
.createQuery(
"select o from Order o join o.items i where i.product=:product"
)
.setParameter(
"product"
,
"foo9"
);
query.setHint(
"org.hibernate.cacheable"
,
true
);
Order other = (Order) query.getSingleResult();
Order other2 = (Order) query.getSingleResult();
assertEquals(
1
, other2.getItems().size());
assertEquals(other, other2.getItems().iterator().next().getOrder());
}
|
ok,大功告成,可以运行测试用例,然后通过日志查看缓存命中率,也可以修改代码
附件:http://down.51cto.com/data/2363915
本文转自sarchitect 51CTO博客,原文链接:http://blog.51cto.com/stevex/1344157,如需转载请自行联系原作者