是的,是不同的东西。
就像 Lee Chee Kiam 所说,一级缓存默认启用,您无法禁用它。
基本上这是 Hibernate 第一次放置获取的实体的地方,因此同一对象的第二次查询不会实例化新对象,甚至可以避免通过 ID 进行查询。一个关于这个的例子here http://howtodoinjava.com/2013/07/01/understanding-hibernate-first-level-cache-with-example/.
//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
我们可以说一级缓存是 Hibernate 的实现身份映射 http://martinfowler.com/eaaCatalog/identityMap.html图案。
查询缓存与实体严格相关,它在搜索条件和满足特定查询过滤器的实体之间建立关联(来自here http://vladmihalcea.com/how-does-hibernate-query-cache-work/)。
查询缓存仅将查询的原始结果作为主键(在 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 的 Person 对应的对象。
查询缓存和二级缓存适用于具有大量读取和很少或零更新的实体。因为众所周知的问题是每种类型的缓存不一致。因此,Hibernate 需要使缓存无效或刷新(如果您有集群缓存,则包括复制)。通过多次更新,您将不断地使缓存失效,这弊大于利。
一些解释取自于此很棒的帖子 http://blog.jhades.org/setup-and-gotchas-of-the-hibernate-second-level-and-query-caches/你应该读一下这个好答案 https://stackoverflow.com/a/1998867/3517383 too.