Hibernate查询缓存LazyInitializationException

Hibernate查询缓存LazyInitializationException,hibernate,spring-boot,spring-data,Hibernate,Spring Boot,Spring Data,我启用了二级缓存和查询缓存,当我有一个缓存的查询时,我面临一个奇怪的问题。实体中的所有关系都已初始化。下面是我正在查询的实体的一个示例: @Entity @Cache(usage = READ_WRITE) @Data @NoArgsConstructor @Accessors @EqualsAndHashCode(of = "id", callSuper = false) public class TestEntity { /** The Constant serialVersionUI

我启用了二级缓存和查询缓存,当我有一个缓存的查询时,我面临一个奇怪的问题。实体中的所有关系都已初始化。下面是我正在查询的实体的一个示例:

@Entity
@Cache(usage = READ_WRITE)
@Data
@NoArgsConstructor
@Accessors
@EqualsAndHashCode(of = "id", callSuper = false)
public class TestEntity {

  /** The Constant serialVersionUID. */
  private static final long serialVersionUID = 1L;

  @Id
  @Column(updatable = false)
  private Long id;

  @OneToOne(cascade = ALL, fetch = LAZY)
  private AnotherTestEntity anotherTestEntity;

}

@Entity
@Cache(usage = READ_WRITE)
@Data
@NoArgsConstructor
@Accessors
@EqualsAndHashCode(of = "id", callSuper = false)
public class AnotherTestEntity {

  /** The Constant serialVersionUID. */
  private static final long serialVersionUID = 1L;

  @Id
  @Column(updatable = false)
  private Long id;

  @Column
  private String property;

}
执行未缓存的查询时:

@Transactional(readOnly = true)
public TestEntity findTestEntity() {
  TestEntity testEntity = testEntityRepository.findOne(1);
  testEntity.getAnotherTestEntity().getProperty(); 

  return testEntity;
}
第一次调用此方法时,它查询数据库并将实体添加到二级缓存中。第二次调用它时,它从二级缓存加载实体,它仍然可以正常工作

当我调用缓存的查询时,问题就出现了。以下是一个例子:

@Repository
public interface TestEntityRepository {

  @Cachable(cacheNames = "testQuery")
  TestEntity findOne(Long id);
}
我将使用相同的方法:

@Transactional(readOnly = true)
public TestEntity findTestEntity() {
  TestEntity testEntity = testEntityRepository.findOne(1);
  testEntity.getAnotherTestEntity().getProperty(); 

  return testEntity;
}
当我第一次调用它时,它仍然可以正常工作——从数据库加载数据。当第二次调用使用查询缓存时,问题就出现了。当我访问惰性初始化关系时引发此异常:

Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session

我可以看到惰性初始化实体的会话为null,但我不明白为什么会发生这种情况。正如我们所知,查询缓存只包含与该查询关联的实体的ID,然后它从L2(引用:)中检索它们。因此,我无法理解为什么第一个示例(没有查询缓存)运行良好,而第二个示例的行为如此怪异。有人能解释并告诉我我做错了什么吗?

这可能是一个bug,但可以肯定的是,您需要使用最新的Hibernate ORM复制它


如果您无法复制它,这意味着问题已经解决,您需要升级Hibernate,或者问题源于Spring,而不是Hibernate。

所以我就深入研究了这个问题,结果证明Spring缓存抽象不能与Hibernate延迟加载代理一起使用。Spring为您提供了一个抽象概念,他们不知道hibernate和hazelcast。然后,hazelcast提供了与spring一起工作的实现。因此,当使用@Cachable注释的方法被调用时,Spring方面会检查缓存(使用提供的CacheManager——在本例中为HazelcastCacheManager)并检索缓存中的内容。这里的问题是,hibernate代理中的会话是暂时的(这种方式是绝对正常的),因此我们从缓存中检索一个没有hibernate会话的实体,并且由于spring不想与hibernate耦合,因此没有设置会话。然后我们收到LazyInitializationException。但归根结底,这是一个非常普遍的问题,奇怪的是,到了春天还没有一个解决办法。有效的方法是使用hibernate查询缓存,使用hazelcast还有其他一些缺点