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(); 
     } 
    }); 
}