Spring JpaRepository:delete() 和后续 save() 在同一事务中

我的实体同时具有自动生成的主键 (id) 和业务键(命名空间)。我需要通过替换旧记录来更新记录。因此,我正在按业务键搜索它,删除它并保存一个新实体。如果每个操作都属于自己的事务,则此方法有效。但是一旦我把它们都放在同一个事务中,到执行 save() 时,delete() 还没有执行,所以我得到了一个约束冲突。

transactionTemplate.execute(status -> {
    MyEntity oldEntity = repository.findByNamespace(namespace);
    if (oldEntity != null) {
        repository.delete(oldEntity);
    }
    repository.save(newEntity);
    return null;
});

我实际上设法通过添加

repository.flush();

但我真的不明白为什么我需要这个冲洗()。


答案 1

因为 repository.flush() 通过调用 EntityManager.flush() 将更改刷新到数据库。因此,当您在delete()之后刷新更改时,sql将被执行,并且以下保存将没有问题。

如果不调用 flush,则由持久性提供程序确定何时刷新更改,事务提交时间是截止时间。此外,提供程序不会按任何特定顺序刷新更改,因此有时您的操作可能会成功,有时操作不会成功。通常,提供程序会等到提交时间刷新,但您可以通过设置刷新模式来影响这一点:

for entitymanager
EntityManager.setFlushMode(FlushModeType type);

or for query
Query.setFlushMode(FlushModeType type);

我敢肯定,在Spring数据JPA中也有一个等效的设置,但我并不完全知道它是哪一个。

但请注意,立即刷新更改会降低性能,因此在使用它时应小心。在您的特定情况下,最好更新实体,然后删除它,然后使用相同的业务密钥保留新的实体。


答案 2

推荐