我的实体有自动生成的主键(id)和业务键(命名空间)。我需要通过替换旧的来更新记录。因此,我通过业务密钥搜索它,删除它并保存一个新实体。如果每个操作都在它自己的事务中,则此方法有效。但是一旦我把它们都放在同一个事务中,在执行保存()的时候,delete()还没有执行,所以我得到了一个约束冲突。
transactionTemplate.execute(status -> {
MyEntity oldEntity = repository.findByNamespace(namespace);
if (oldEntity != null) {
repository.delete(oldEntity);
}
repository.save(newEntity);
return null;
});
字符串
实际上我成功地绕过了它
repository.flush();
型
但是我真的不明白为什么我需要这个同花。
2条答案
按热度按时间li9yvcax1#
因为repository.flush()通过调用EntityManager.flush()来刷新数据库中的更改。因此,当您在delete()之后刷新更改时,SQL将被执行,并且随后的保存将不会有任何问题。
如果不调用flush,则由持久性提供程序来决定何时刷新更改,事务提交时间是截止日期。此外,提供程序不会以任何特定的顺序刷新更改,因此有时您的操作成功,有时却失败。通常,提供程序会等到提交时刷新,但您可以通过设置刷新模式来影响该操作:
字符串
我确信SpringdataJPA中也有一个等效的设置,但我不知道是哪一个。
但是请注意,立即刷新更改会降低性能,因此在使用它时应小心。在您的特定情况下,最好更新实体,然后删除它,然后使用相同的业务密钥持久化新实体。
cfh9epnr2#
我遇到了同样的问题,我需要首先删除对象,然后创建一个新对象,但得到了违反约束的异常,因为删除没有被刷新到DB,插入也因此失败。
我尝试了
delete*
方法的各种不同的方法,但只有deleteInBtraiatch(Iterable<T> entity)
起作用。