这看起来很简单。我尝试了很多但是失败了。
据我所知,Hibernate一级缓存意味着会话级缓存。当我们在同一个会话中多次检索同一个对象时,它将从Cache中检索。
例如,我在数据库中有一个ID为100的员工记录。
我打开一个会话并获取该员工对象。直到我关闭该对象在同一会话中可用的会话。
问题:为什么我需要在同一个会话中多次检索同一个对象(在我关闭它之前,它是如何在会话中使用的那样)?
答案 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)
这取决于您如何管理Session
或EntityManager
。如果是按请求创建的,则无需再次查询。但是如果重用Session
/ EntityManager
,则可以多次检索同一个对象,以便从第一级缓存返回。