设置休眠第二级缓存

问题描述:

我是新的休眠和春季,我试验休眠二级缓存。但它似乎不起作用。我有以下测试类:设置休眠第二级缓存

@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] 

我有什么做的就是它的工作?

+0

实体类本身必须作出明确缓存 - 你这样做呢? – skaffman 2011-03-03 13:51:42

+0

是的,我有@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) – Daniel 2011-03-03 13:55:30

您的测试看起来很奇怪,您为每个测试创建一个新的应用程序上下文,因此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); 
    }  
} 
+0

感谢您的回答。但是什么是@Autowired public void setPtm(PlatformTransactionManagement ptm){txt = new TransactionTemplate(ptm); }和专门的PlatformTransactionManagement? – Daniel 2011-03-03 14:41:26

+0

@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

+0

我执行你的代码,但现在我得到 行数: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项目,所以,你可以将它与你的代码比较:

https://issues.jboss.org/browse/JBPAPP-4224