看起来很简单的问题。我试了很多,但失败了。使用休眠一级缓存
据我所知,Hibernate一级缓存意味着会话级缓存。当我们在同一会话中多次检索同一对象时,它将从缓存中检索。
例如,我在数据库中有一个ID为100的员工记录。
我打开了一个会话并获得该员工对象。直到我关闭会话该对象在同一会话中可用。
问题:为什么我需要在同一个会话中多次检索同一对象(任何它在会话中的可用状态,直到关闭它为止)?
看起来很简单的问题。我试了很多,但失败了。使用休眠一级缓存
据我所知,Hibernate一级缓存意味着会话级缓存。当我们在同一会话中多次检索同一对象时,它将从缓存中检索。
例如,我在数据库中有一个ID为100的员工记录。
我打开了一个会话并获得该员工对象。直到我关闭会话该对象在同一会话中可用。
问题:为什么我需要在同一个会话中多次检索同一对象(任何它在会话中的可用状态,直到关闭它为止)?
据我所知,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()
等)
你不需要需要从EntityManager中多次检索同一个对象,但是如果你这样做,你会得到同样的对象。这就是缓存的意义。至于你的第二个问题:EntityManager保持对这个对象的引用,并且如果你再次请求同一个对象,则返回它。
我建议通过JPA教程,如http://docs.oracle.com/javaee/6/tutorial/doc/bnbpz.html。恕我直言,您应该专注于学习JPA并将Hibernate简单地视为JPA提供者。
如果存在该员工对象需要检索做出后续调用,它可以从同一个会话中获得,而不是从DB
这取决于你如何管理Session
或EntityManager
。如果它是根据请求创建的,则不需要再次查询它。但是如果Session
/EntityManager
被重用,那么可以多次检索同一个对象,因此它将从第一级缓存中返回。