2016-09-14 84 views
1

看起来很简单的问题。我试了很多,但失败了。使用休眠一级缓存

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

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

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

问题:为什么我需要在同一个会话中多次检索同一对象(任何它在会话中的可用状态,直到关闭它为止)?

回答

1

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

它是一半正确的。除了你所说的,一级缓存的一个主要原因是,在同一会话下,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将简单地获取该实例并返回给您。

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

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

(假设上面的发现者在内部运行的查询通Hibernate会话)当Hibernate运行查询第二,内部休眠运行SQL,得到结果集,每条记录转换为一个用户。假设其中一个活动用户具有ID 777.当Hibernate构造该User对象实例时,它将首先检查它是否存在于第一级缓存中。因为它先前被检索过(在以前的查询中可以通过用户名找到),所以Hibernate不会构造一个新的User对象实例,而是简单地重用先前构建的实例(并存储在第一级缓存中)并将其用于结果列表中。通过这样做,Hibernate可以确保在同一个会话中,如果您通过不同的方式检索同一个实体(具有相同ID的同一个类),您可以始终假定该实体将是同一个对象实例。

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


对于

的问题是在会话中可用如何,直到我关闭它

更休眠的内部实现细节。然而,从概念上讲,你可以想象得到,每个会话内部都有一个Map,关键是实体类型+ ID,值是实体对象实例。

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

类似的想法时,你得到的ID实体(直通Session.get()Session.load()等)

0

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

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

0

如果存在该员工对象需要检索做出后续调用,它可以从同一个会话中获得,而不是从DB

0

这取决于你如何管理SessionEntityManager。如果它是根据请求创建的,则不需要再次查询它。但是如果Session/EntityManager被重用,那么可以多次检索同一个对象,因此它将从第一级缓存中返回。