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

据我所知,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()等)获取实体时,类似的想法

09-26 17:57
查看更多