看起来很简单。我尝试了很多,但失败了。
据我所知,Hibernate一级缓存意味着会话级缓存。当我们在同一会话中多次检索同一对象时,它将从Cache中检索。
例如,我在数据库中有一个ID为100的Employee记录。
我打开了一个会话并获取了该员工对象。直到关闭会话为止,该对象在同一会话中可用。
问题:为什么我需要在同一会话中多次检索同一对象(在关闭会话之前,该对象在会话中如何可用)?
最佳答案
据我所知,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,获取结果集,并将每个记录转换为User。假设一个 Activity 用户的ID为777。当Hibernate构造该User对象实例时,它将首先检查它是否存在于一级缓存中。因为它是先前检索的(在先前的查询中按用户名查找),所以Hibernate无需构造新的User对象实例,而是仅重用先前构造(并存储在一级缓存中)的实例,并将其用于结果列表中。
这样,Hibernate可以确保在同一会话中,如果您通过不同的方式检索相同的实体(具有相同ID的同一类),则始终可以假定该实体将是相同的对象实例。
考虑一个更复杂的示例,您正在尝试从系统中检索
Order
,它引用了User
(假设多对一)。您将发现的是不同的Order
,每当它引用相同的User
(在数据库中)时,实际上是在引用相同的User
对象实例。对于的问题
在会话中如何使用它,直到我将其关闭
它更多是Hibernate的内部实现细节。但是,从概念上讲,您可以想象它是,每个Session在内部都有一个Map,键是Entity Type + ID,值是实体对象实例。
当您从数据库中查询时,以及当会话为您构造实体时,对于每个实体,它将从地图中查找(如果已存在)。如果没有,会话将构造实体并放入地图中。如果已经存在,会话将仅使用地图中的实体
当通过ID(通过
Session.get()
或Session.load()
等)获取实体时,类似的想法