设置休眠第二级缓存
我是新的休眠和春季,我试验休眠二级缓存。但它似乎不起作用。我有以下测试类:设置休眠第二级缓存
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
@TransactionConfiguration
@Transactional
public class CacheTest extends AbstractTransactionalJUnit4SpringContextTests
{
@Test
public void testCache1()
{
System.out.println("Running testCache1");
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
MutableDAO<AppUser> appUserDAO = new MutableDAOImpl<AppUser>(AppUser.class, (SessionFactory) ctx.getBean("OnMediaSessionFactory"), 10);
assertNotNull("AppUser DAO is null.", appUserDAO);
SessionFactory sessionFactory = (SessionFactory)ctx.getBean("OnMediaSessionFactory");
long numberOfUsers = appUserDAO.countAll();
System.out.println("Number of rows :" + numberOfUsers);
final String cacheRegion = AppUser.class.getCanonicalName();
SecondLevelCacheStatistics settingsStatistics = sessionFactory.getStatistics().
getSecondLevelCacheStatistics(cacheRegion);
StopWatch stopWatch = new StopWatch();
stopWatch.start();
appUserDAO.findAll();
stopWatch.stop();
System.out.println("Query time : " + stopWatch.getTotalTimeSeconds());
System.out.println(settingsStatistics);
}
@Test
public void testCache2()
{
System.out.println("Running testCache2");
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
MutableDAO<AppUser> appUserDAO = new MutableDAOImpl<AppUser>(AppUser.class, (SessionFactory) ctx.getBean("OnMediaSessionFactory"), 10);
assertNotNull("AppUser DAO is null.", appUserDAO);
SessionFactory sessionFactory = (SessionFactory)ctx.getBean("OnMediaSessionFactory");
long numberOfUsers = appUserDAO.countAll();
System.out.println("Number of rows :" + numberOfUsers);
final String cacheRegion = AppUser.class.getCanonicalName();
SecondLevelCacheStatistics settingsStatistics = sessionFactory.getStatistics().
getSecondLevelCacheStatistics(cacheRegion);
StopWatch stopWatch = new StopWatch();
stopWatch.start();
appUserDAO.findAll();
stopWatch.stop();
System.out.println("Query time : " + stopWatch.getTotalTimeSeconds());
System.out.println(settingsStatistics);
}
}
和我有
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
,但我得到的输出是这样的:
Running testCache1
Number of rows :81
Query time : 0.129
SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=81,elementCountInMemory=81,elementCountOnDisk=0,sizeInMemory=219634]
Running testCache2
Number of rows :81
Query time : 0.063
SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=81,elementCountInMemory=81,elementCountOnDisk=0,sizeInMemory=219634]
我有什么做的就是它的工作?
您的测试看起来很奇怪,您为每个测试创建一个新的应用程序上下文,因此Hibernate SessionFactory
在测试之间以及它的二级缓存之间并不存在。
正确的测试应该是这样的:
所有的@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
public class CacheTest extends AbstractTransactionalJUnit4SpringContextTests
{
@Autowired
private MutableDAO<AppUser> appUserDAO;
@Autowired
private SessionFactory sessionFactory;
private TransactionTemplate tx;
@Autowired
public void setPtm(PlatformTransactionManagement ptm) {
tx = new TransactionTemplate(ptm);
}
@Test
public void doTestCache() {
// Using programmatic transaction management since we need 2 transactions
// inside the same method
// 1st attempt
tx.execute(new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(TransactionStatus status) {
testCache();
}
});
// 2nd attempt
tx.execute(new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(TransactionStatus status) {
testCache();
}
});
}
public void testCache() {
long numberOfUsers = appUserDAO.countAll();
System.out.println("Number of rows :" + numberOfUsers);
final String cacheRegion = AppUser.class.getCanonicalName();
SecondLevelCacheStatistics settingsStatistics = sessionFactory.getStatistics().
getSecondLevelCacheStatistics(cacheRegion);
StopWatch stopWatch = new StopWatch();
stopWatch.start();
appUserDAO.findAll();
stopWatch.stop();
System.out.println("Query time : " + stopWatch.getTotalTimeSeconds());
System.out.println(settingsStatistics);
}
}
感谢您的回答。但是什么是@Autowired public void setPtm(PlatformTransactionManagement ptm){txt = new TransactionTemplate(ptm); }和专门的PlatformTransactionManagement? – Daniel 2011-03-03 14:41:26
@Daniel:编程事务管理需要它,参见[10.6编程事务管理](http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#transaction -programmatic)。由于您想检查缓存值在事务之间是否存在,因此您需要在测试方法内执行多个事务,而编程事务管理是安排它的好方法。 – axtavt 2011-03-03 14:46:21
我执行你的代码,但现在我得到 行数:81 查询时间:0。142个 SecondLevelCacheStatistics [hitCount = 0,missCount = 0,putCount = 0,elementCountInMemory = 0,elementCountOnDisk = 0,sizeInMemory = 0] 行数:81 查询时间:0.031 SecondLevelCacheStatistics [hitCount = 0,missCount = 0, putCount = 0,elementCountInMemory = 0,elementCountOnDisk = 0,sizeInMemory = 0] – Daniel 2011-03-03 15:50:18
首先,请记住,Hibernate并不默认使用任何缓存提供者。所以,你需要一个Hibernate的2L缓存的“外部”缓存提供者。对于我的回答,我将使用ehcache和Hibernate 3.3。请注意,在更新版本的Hibernate中配置已更改,因此请阅读您正在使用的确切版本的文档。
在您的Hibernate配置中,您错过了一个部分,即将Hibernate指向实际的提供者。该属性hibernate.cache.provider_class
为Hibernate 3.3做到了这一点。设置它的价值net.sf.ehcache.hibernate.SingletonEhCacheProvider
现在,你还需要一个ehcache.xml中,像这样:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="./cache" />
<defaultCache maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="FIFO" />
<cache name="com.mycompany.jpa.MyEntity"
maxElementsInMemory="50"
overflowToDisk="true" />
<cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50"
overflowToDisk="true" />
<cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000"
overflowToDisk="true" />
</ehcache>
你没有表现出你的DAO,所以,我不知道它的正确与否。请注意,您始终需要明确缓存,因为它旨在用于特定位置的解决方案,而不是一切的通用解决方案。这意味着,在你的DAO中,你会添加一个查询提示,指出你的查询是可缓存的(从你的测试看来,你似乎想要查询缓存,而不仅仅是实体缓存)。
如果您仍然无法使其工作,请参阅以下JIRA中的附件。它包含启用缓存Maven项目,所以,你可以将它与你的代码比较:
实体类本身必须作出明确缓存 - 你这样做呢? – skaffman 2011-03-03 13:51:42
是的,我有@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) – Daniel 2011-03-03 13:55:30