Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 更新子实体但保存父实体会导致ObjectOptimisticLockingFailureException_Java_Spring_Spring Boot_Jpa_Optimistic Locking - Fatal编程技术网

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