Hibernate一级缓存与查询缓存

时间:2013-10-22 11:21:27

标签: hibernate query-cache first-level-cache

第一级缓存是否与hibernate中的查询缓存不同?我看过有关第一级和查询缓存的文章,所以我很困惑。

2 个答案:

答案 0 :(得分:9)

是的,是不同的事情。 就像Lee Chee Kiam所说的那样,默认情况下启用了第一级缓存,您无法禁用它。 基本上它是Hibernate第一次放置获取的实体的位置,因此同一对象的第二个查询不会实例化新对象,甚至可以通过ID来避免查询。关于此here的一个示例。

//Open the hibernate session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();

//fetch the department entity from database first time
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//fetch the department entity again
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

session.getTransaction().commit();
HibernateUtil.shutdown();

Output:

Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource
Human Resource

我们可以说第一级缓存是IdentityMap模式的Hibernate实现。

查询缓存与实体严格相关,它在搜索条件和实现该特定查询过滤器的实体之间绘制关联(来自here)。 查询缓存仅将查询的原始结果保存为主键,在hibernate中,id为。 它不包含实际的水合物

查询缓存如何工作?

假设我们有以下条件查询:

session.createCriteria(Person.class)
    .add( Restrictions.eq("firstName", "Joey")
    ).setCacheable(true);

查询缓存在概念上看起来像一个哈希映射,其中密钥由查询文本和参数值组成,值是与查询匹配的实体ID列表

*----------------------------------------------------------*
|                       Query Cache                        |                     
|----------------------------------------------------------|
| ["from Person where firstName=?", ["Joey"] ] -> [1, 2] ] |
*----------------------------------------------------------*

因此,下次我们执行相同的条件查询时,Hibernate会查看该哈希映射并解析id为1和2的人匹配限制。 在这种情况下,您将避免查询的成本(在这种情况下几乎为零,但可能是一个昂贵的查询与连接等)但你仍然会在数据库中查询人员(现在通过id是什么非常快)用于构造Person对象。 查询缓存经常与二级缓存一起使用,这需要第三部分实现,如Ehcache或infinispan。

二级缓存存储实体数据,但不存储实体本身。数据以“脱水”格式存储,其看起来像哈希映射,其中密钥是实体Id,并且值是原始值列表。 下面是一个关于二级缓存内容如何显示的示例:

*-----------------------------------------*
|          Person Data Cache              |
|-----------------------------------------|
| 1 -> [ "Joey" , "Q" , "Public" , null ] |
| 2 -> [ "Joey" , "D" , "Public" ,  1   ] |
| 3 -> [ "Sara" , "N" , "Public" ,  1   ] |
*-----------------------------------------*

因此,查询缓存将为我们提供ID 1和2,然后Hibernate将在二级缓存中构造具有原始数据的对象,该缓存对应于ID为1和2的人。

查询缓存和二级缓存适用于具有许多读取且很少或零更新的实体。因为众所周知的每种类型的缓存都存在不一致的问题。因此,Hibernate将需要使缓存无效或刷新缓存(如果您有群集缓存,则包含复制)。通过许多更新,您将不断地使缓存失效,这将弊大于利。

有些解释来自此great post,您也应该阅读此good answer

答案 1 :(得分:2)

默认情况下启用第一级缓存,并且是基于每个会话。默认情况下不启用查询缓存,跨多个会话共享,并且应始终与二级缓存一起使用。

要启用查询缓存,应使用以下属性:

hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=org.hibernate.cache.EhCacheProvider
hibernate.cache.use_query_cache=true