【问题标题】:Hibernate query cache LazyInitializationExceptionHibernate 查询缓存 LazyInitializationException
【发布时间】:2018-11-18 05:20:37
【问题描述】:

我启用了 L2 和查询缓存,当我有一个缓存的查询时,我遇到了一个奇怪的问题。实体中的所有关系都是惰性初始化的。这是我正在查询的实体的示例:

@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;
}

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

当我调用一个缓存的查询时,问题就来了。这是一个例子:

@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

我可以看到惰性初始化实体的会话为空,但我不知道为什么会这样。正如我们所知,查询缓存仅包含与该查询关联的实体的 ID,然后它会从 L2 中检索它们(参考:https://dzone.com/articles/pitfalls-hibernate-second-0)。所以我不明白为什么第一个例子(没有查询缓存)工作正常,而第二个例子表现得如此奇怪。有人可以解释并告诉我我做错了什么吗?

【问题讨论】:

    标签: hibernate spring-boot spring-data


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      这可能是一个错误,但可以肯定的是,您需要使用 this test case template 将其复制到最新的 Hibernate ORM。

      如果无法重现,则表示问题已修复,您需要升级 Hibernate,或者问题源于 Spring,而不是 Hibernate。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-25
        • 2013-10-31
        • 2014-11-28
        • 2011-12-18
        • 2023-04-03
        • 2011-05-27
        • 1970-01-01
        • 2011-04-03
        相关资源
        最近更新 更多