升级Hibernate 6后L2缓存中复合ID关联懒加载字段异常求助
Hibernate 6 L2缓存异常:复合ID包含懒加载@ManyToOne关联字段时读取缓存报错
环境:
- 数据库:PostgreSQL 14.5、H2 2.1.214
- 框架版本:从Hibernate 5.6.15升级至Hibernate 6.1.7~6.2.3、Spring Data JPA 3.0.6、Spring Boot 3.0.7
- 缓存:Ehcache 3.10.8
- JDK:OpenJDK Temurin 17.0.6
实体定义
Product 实体
@Getter @IdClass(ProductPK.class) @EqualsAndHashCode(onlyExplicitlyIncluded = true) @ToString(onlyExplicitlyIncluded = true) @NoArgsConstructor(access = PROTECTED) @Entity @OptimisticLocking(type = OptimisticLockType.ALL) @DynamicUpdate @Cacheable @Cache(usage = READ_WRITE) @Table(name = "PRODUCTS") public class Product { public Product(String productId, Operator operator) { this.productId = productId; this.operator = operator; } @EqualsAndHashCode.Include @ToString.Include @Id @Column(name = "PRODUCT_ID", nullable = false) private String productId; @Id @EqualsAndHashCode.Include @ToString.Include @Getter @Setter @ManyToOne(fetch = LAZY) @JoinColumn private Operator operator; @Column(name = "DESCRIPTION") @Setter private String description; @AllArgsConstructor @EqualsAndHashCode @Getter @Setter @NoArgsConstructor(access = PRIVATE) public static class ProductPK implements Serializable { private String productId; private String operator; } }
Operator 实体
@Getter @Entity @ToString(onlyExplicitlyIncluded = true) @EqualsAndHashCode(onlyExplicitlyIncluded = true) @NoArgsConstructor(access = PROTECTED) @Table(name = "OPERATORS") @OptimisticLocking(type = OptimisticLockType.DIRTY) @DynamicUpdate @Cacheable @Cache(usage = READ_WRITE) public class Operator { public Operator(String operatorId) { this.operatorId = operatorId; } @EqualsAndHashCode.Include @ToString.Include @Id @Column(name = "OPERATOR_ID", nullable = false) private String operatorId; @OneToMany(mappedBy = "operator", cascade = {CascadeType.ALL}, orphanRemoval = true) private List<Product> products = new ArrayList<>(); public void setProducts(List<Product> products) { this.products = products; } }
测试用例及异常
测试1
连续两次调用带有@Transactional(propagation = REQUIRES_NEW)的getProduct方法,第二次从L2缓存读取时抛出异常:
Caused by: org.hibernate.HibernateException: identifier of an instance of com.example.demo.local.Product was altered from com.example.demo.local.Product$ProductPK@226fd to com.example.demo.local.Product$ProductPK@44bf91
测试2
首次读取后,在带有@Transactional(readOnly = true)的readProduct方法中从缓存读取时抛出空指针异常,Hibernate似乎未识别operator为懒加载字段:
java.lang.NullPointerException: Cannot invoke "com.example.demo.local.Operator.getOperatorId()" because the return value of "com.example.demo.local.Product.getOperator()" is null
已在Hibernate官方仓库提交问题(HHH-16673),目前暂未收到回复,现寻求可行的解决方法或临时规避方案。
内容的提问来源于stack exchange,提问作者BummyWatermoon
相关产品推荐
相关产品推荐

