Java 更新子实体但保存父实体会导致ObjectOptimisticLockingFailureException
我有这样一个实体:Java 更新子实体但保存父实体会导致ObjectOptimisticLockingFailureException,java,spring,spring-boot,jpa,optimistic-locking,Java,Spring,Spring Boot,Jpa,Optimistic Locking,我有这样一个实体: class Parent { @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER) private List<ChildUpdatedByBatch> childrenUpdatedByBatch; @OneToOne(mappedBy = "parent", cascade = CascadeType.ALL) pri
class Parent {
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<ChildUpdatedByBatch> childrenUpdatedByBatch;
@OneToOne(mappedBy = "parent", cascade = CascadeType.ALL)
private Child child;
....
}
// updating parent entity by adding/ or updating a ChildUpdatedByBatch
parentRepository.save(parent);
常规行动还使用:
// updating parent entity by adding/ or updating the Child entity
parentRepository.save(parent);
但第二个(常规操作)是抛出ObjectOptimisticLockingFailureException,因为
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [<package>.ChildEntityUpdatedByBatch#911].
或者,如果这也不能解决问题。为
子项添加存储库当然是明智的,但我怀疑它是否能解决您的问题
您仍然需要用子对象更新父对象,这样您仍然有两个parentRepository.save(parent)如果我正确理解您的案例,代码>操作。因此,无论如何,在某个时刻,您最终会遇到一个OptimisticLockException
我将简单地应用处理此类例外情况的一般程序,即:
- 捕获
OptimisticLockException
- 合并发生保存异常的实体
- 再次重试持久化/更新
正如我所想,我也遇到了类似的问题,也许我能稍微澄清一下问题的根源
MySQL JDBC驱动程序(和MySQL数据库)使用REPEATABLE READ
作为默认事务隔离级别。例如,它比Oracle默认的读取提交的级别受到更大的限制
那么在我看来会发生什么呢
事务X
打开
Hibernate加载了10条子记录的Parent
另一个事务Y
启动并删除了来自同一父项的所有子项
记录
可重复读取
意味着,如果您将在事务X
中再次加载父项
,您将看到相同的10个子项
记录,如Y
未执行任何操作
但是!当您想要删除/更新事务中的子记录时,Hibernate将执行该操作,但delete/update会返回受影响记录的数量
因此,这是一件棘手的事情-受影响的记录数将等于零,因为事务Y
已删除所有记录(这称为幻影读取)。但是Hibernate认为他应该删除10条记录。在收到0条已删除的记录后,Hibernate将上升ObjectOptimisticLockingFailureException
,因为Hibernate认为这种情况是异常的
我通过在MySQL JDBC驱动程序的属性中将事务隔离级别更改为readcommitted
,解决了这个问题
MySQL中可重复读取隔离级别的实现非常棘手,因此您可以参考本文。它对这个话题有很好的解释
您使用什么数据库?我使用mysql数据库
child.save(child) // with child having a reference to out-of-date parent