打开Hibernate查询缓存时,默认情况下是否缓存本机SQL查询?

时间:2011-04-21 06:55:53

标签: hibernate caching ehcache

使用Hibernate 3.3.0和ehcache 1.2.3启用了二级缓存和查询缓存,我意识到以下代码在多个调用中返回相同的序列号,导致插入失败。

        HibernateCallback callback = new HibernateCallback()
        {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                StringBuilder strQuery = new StringBuilder();
                strQuery.append("SELECT ");
                strQuery.append(sequenceName);
                strQuery.append(".nextval as nextSequence FROM dual d");

                Query query = session.createSQLQuery(strQuery.toString()).addScalar("nextSequence", Hibernate.STRING);


                return query.uniqueResult();
            }
        };
        return this.hibernateTemplate.execute(callback).toString();

如果我在执行查询之前关闭查询缓存或添加以下行,代码将正常工作。

query.setCacheable(false);

这很令人困惑,因为Hibernate文档清楚地说明了

  

大多数查询都没有从中受益   缓存,所以默认查询不是   缓存。要启用缓存,请致电   Query.setCacheable(真)。这个电话   允许查询查找现有查询   缓存结果或将结果添加到   执行时的缓存。

在这种情况下,这种异常行为是否仍然可以假设默认情况下不会缓存查询?

1 个答案:

答案 0 :(得分:4)

查询缓存是一种非常简单的机制,可以存储某些密钥的结果。在本机查询的情况下,密钥将是您的查询本身和所有参数。

因此,例如,密钥可能是:

*----------------------------------------------------------------------------------------*
|                                    Query Cache                                         |
|----------------------------------------------------------------------------------------|
| ["select * from table as t where t.id=? and p.column=?", [ 1 , "value"] ] -> [  2 ] ]  |
*----------------------------------------------------------------------------------------*

从这个角度来看,每个查询都可以缓存 - 在某些情况下。当然,查询必须由Hibernate类处理,而不是直接通过JDBC连接处理。

而且,顺便说一下,很容易发现你的查询是否会使用查询缓存!它全部位于org.hibernate.cache下的日志文件中。

所有这些都有一个很大的问题 - 如果你运行你的本机查询,它将驱逐二级缓存的所有实体和记录!至少它直到我使用的最后一个版本!所以你可以使用本机查询,但由于Hibernate无法决定它们做什么,它将清除缓存以避免此查询所做的数据更改未反映在缓存对象中。

因此查询缓存存在很多问题,您应该考虑是否真的想要使用该功能! Take a look at this articlethis one。我试图避免在我的工作中使用查询缓存,我只使用SLC实体......