我的实体同时具有自动生成的主键(id)和业务键(命名空间)。我需要通过替换旧记录来更新记录。因此,我按业务键搜索,删除它并保存新实体。如果其中的每个操作都是自己的事务,则此方法有效。但是,一旦我将所有这些都放在同一个事务中,当执行save()时,delete()还没有被执行,所以我得到了一个约束违规。
transactionTemplate.execute(status -> {
MyEntity oldEntity = repository.findByNamespace(namespace);
if (oldEntity != null) {
repository.delete(oldEntity);
}
repository.save(newEntity);
return null;
});
我实际上设法通过添加
来绕过它repository.flush();
但我真的不知道为什么我需要这个冲洗()。
答案 0 :(得分:8)
因为repository.flush()通过调用EntityManager.flush()来刷新对数据库的更改。因此,当您在delete()之后刷新更改时,会执行sql并且以下保存没有问题。
如果不调用flush,则由持久性提供程序决定何时刷新更改,事务提交时间为截止日期。提供者也不会以任何特定顺序刷新更改,因此有时您的操作会成功,有时则不会。通常,提供者会等到提交时间刷新,但您可以通过设置刷新模式来影响它:
for entitymanager
EntityManager.setFlushMode(FlushModeType type);
or for query
Query.setFlushMode(FlushModeType type);
我确信Spring数据JPA中还有一个等效的设置,但我不知道它是哪一个。
但请注意,立即刷新更改会降低性能,因此在使用时应小心。在您的特定情况下,最好更新实体,然后删除它,然后使用相同的业务键保留新实体。