2011-08-17 93 views
3

在我們的一些代碼中,我們使用HibernateDaoSupport的setCacheQueries()方法。起初,我們有一個函數getByGroupId(),它只叫setCacheQueries(true),但是當進行集成測試時,這導致Hibernate拋出「重複的異常」。 所以我搜索了一下,看到有很多人在查詢之前使用了啓用緩存的模式,之後將其禁用。然後,我在查詢後嘗試禁用緩存,並且重複錯誤消失。現在我想知道這種模式的確在做什麼?下面的代碼模仿這種模式。getHibernateTemplate()。setCacheQueries()應該如何正確使用?

import org.springframework.orm.hibernate3.support.HibernateDaoSupport; 
public class MyDao extends HibernateDaoSupport{ 

    public List getByGroupId(Long groupId) { 
    getHibernateTemplate().setCacheQueries(true); 
    List result = getHibernateTemplate().find(
        "from Selection where groupId = ? order by sortOrder ASC", groupId); 
    getHibernateTemplate().setCacheQueries(false); 
    return result; 
    } 
} 

我不確定Spring和Hibernate是如何在這裏一起工作的。如果setCacheQueries(false)會清空所有緩存的查詢,那麼這將毫無意義,但如果它只是禁用稍後查詢的緩存(直到調用setCacheQueries(true)),它會更有意義。

  • 這種模式在查詢前後開啓/關閉緩存正常嗎?
  • 它工作(即查詢緩存)嗎?
  • 任何想法爲什麼它會導致Hibernate在查詢後沒有調用setCacheQueries(false)時拋出有關重複條目的異常?

回答

8

當的HibernateTemplate的cacheQueries屬性爲true,它會自動使每QueryCriteria執行緩存。即它在執行查詢/標準之前調用Query.setCacheable(true)和Criteria.setCacheable(true)。

因此,您的模式實際上是讓您要執行可緩存的查詢,然後將該標誌重置爲false,以便下一個查詢不會被緩存。

問題是,如果HibernateTemplate被多個線程使用,則使用此模式的結果是不確定的。您可能有一個線程將該標誌設置爲true,然後另一個線程在第一個線程有時間執行其查詢之前立即將其重置爲false。而且由於對該屬性的訪問不同步,您可能也會遇到可見性問題。

我只會在創建HibernateTemplate時使用HibernateTemplate.setCacheable(true),以確保所有所執行的查詢都是可緩存的。如果你不需要它,那麼使用兩個不同的HibernateTemplate實例(一個啓用緩存,另一個不啓用),或者當你需要不同的緩存行爲時直接使用Hibernate API。

關於您的異常,在不知道用例,確切異常及其堆棧跟蹤的情況下,很難診斷。

+0

一切,他說,但如果你需要查詢緩存的細粒度控制,使用[執行() ](http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/hibernate3/HibernateTemplate.html#execute%28org.springframework.orm.hibernate3.HibernateCallback%29)或[executeFind()](http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/hibernate3/HibernateTemplate.html#executeFind%28org.springframework.orm.hibernate3 .HibernateCallback%29)並在查詢對象本身上啓用緩存。 – 2011-08-17 16:44:14

+0

對不起,如果我錯過了這裏的顯而易見的地方,但是當你說「然後將標誌重置爲false以便下一個查詢不可緩存」時,緩存中的查詢到目前爲止是否被緩存從驅逐器關閉時逐出,或他們保持(只是沒有被添加到)?換句話說:在下次調用這個方法時,這個查詢是否會從緩存中取出? – oligofren 2011-08-19 05:47:17

2

JB的答案是正確的錢。除此之外,這裏是你如何可以使每個查詢的緩存,而不是全球整個模板:

public List findBySomething(final int something) { 
    return getHibernateTemplate().execute(new HibernateCallback<List>() { 
     @Override 
     public List doInHibernate(Session session) { 
      Query query = session.createQuery("from Something where something = :something"); 
      query.setParameter("something", something); 
      query.setCacheable(true); 
      return query.list(); 
     } 
    }); 
} 
相關問題