使用Hibernate一级缓存

时间:2016-09-14 05:09:31

标签: java hibernate orm hibernate-cache

这看起来很简单。我尝试了很多但是失败了。

据我所知,Hibernate一级缓存意味着会话级缓存。当我们在同一个会话中多次检索同一个对象时,它将从Cache中检索。

例如,我在数据库中有一个ID为100的员工记录。

我打开一个会话并获取该员工对象。直到我关闭该对象在同一会话中可用的会话。

问题:为什么我需要在同一个会话中多次检索同一个对象(在我关闭它之前,它是如何在会话中使用的那样)?

4 个答案:

答案 0 :(得分:3)

  

据我所知,Hibernate一级缓存意味着会话级缓存。当我们在同一个会话中多次检索同一个对象时,它将从Cache中检索。

这是半正确的。除了你所说的,第一级缓存的一个主要原因是,在同一个会话中,Hibernate将确保相同的实体(具有相同ID的实体)将由相同的对象实例表示。

只有当您通过ID从会话中获取实体时,您所说的才是正确的:

Foo foo1 = session.get(Foo.class, 1L);
Foo foo2 = session.get(Foo.class, 1L);

get()的第一次调用将转到DB加载Foo。当调用第二个调用时,Hibernate将检查在此会话中是否已检索到任何ID为1的Foo。正如之前检索过的那样,Hibernate将简单地获取Foo实例并返回给您。

但是,这种情况并不是最常见的情况,您会看到第一级缓存生效。考虑一下:

// psuedo code only
User user = findByUserName("ADRIAN");  // assume ID = 777
List<User> users = findAllActiveUsers();

(假设上面的查找器在内部运行查询通过Hibernate会话)当Hibernate运行第二个查询时,内部Hibernate运行SQL,获取结果集,并将每个记录转换为用户。假设其中一个活动用户具有ID 777.当Hibernate构造该User对象实例时,它将首先检查它是否存在于第一级缓存中。因为它先前已被检索(在先前的查询中通过用户名查找),而不是构造新的User对象实例,Hibernate将简单地重用先前构建的实例(并存储在第一级缓存中)并在结果列表中使用它。

通过这样做,Hibernate可以在同一个会话中确保如果您通过不同的方式检索相同的实体(具有相同ID的相同类),您始终可以假设该实体将是相同的对象实例。

想想一个更复杂的例子,你试图从你的系统中检索Order,它引用User(假设多对一)。您将发现的是,不同的Order,只要它引用相同的User(在DB中),它实际上是指同一个User对象实例。

关于

的问题
  

在关闭它之前它是如何在会话中使用的

它更像是Hibernate的内部实现细节。但是,从概念上讲,你可以想象它,每个Session内部都有一个Map,关键是Entity Type + ID,值是实体对象实例。

当您从数据库查询并且会话为您构建实体时,对于每个实体,它将从地图中查找它是否已存在。如果没有,会话将构造实体并放入地图。如果它已经存在,会话将只使用地图中的实体

按ID(通过Session.get()Session.load()等)获取实体时的类似想法

答案 1 :(得分:1)

您不需要需要多次从EntityManager中检索同一个对象,但如果这样做,您将获得相同的对象。这就是缓存的意义所在。至于你的第二个问题:EntityManager保留对这个对象的引用,如果再次请求同一个对象,则返回它。

我建议您使用像http://docs.oracle.com/javaee/6/tutorial/doc/bnbpz.html这样的JPA教程。恕我直言,你应该专注于学习JPA并简单地将Hibernate视为JPA提供者。

答案 2 :(得分:1)

如果后续调用需要检索此员工对象,则可以从同一会话获取,而不是从DB

获取

答案 3 :(得分:1)

这取决于您如何管理SessionEntityManager。如果是按请求创建的,则无需再次查询。但是如果重用Session / EntityManager,则可以多次检索同一个对象,以便从第一级缓存返回。