2011-03-03 127 views
5

我是新的休眠和春季,我試驗休眠二級緩存。但它似乎不起作用。我有以下測試類:設置休眠第二級緩存

@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

回答

3

您的測試看起來很奇怪,您爲每個測試創建一個新的應用程序上下文,因此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

2

首先,請記住,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