场景:
代码报错,显示某个表触发了唯一索引,但是出错位置却在查询语句上,保存的表在之前有先delete后再save操作,且上述数据库操作都在@Transactional控制下。
分析:
表触发唯一索引,说明是有两条数据有唯一冲突导致的,查询该表的数据库操作,发现有先delete后再save,且查询/删/增都在@Transactional控制下,可能是查询语句需要实际访问数据库,带着之前的删除/新增一起在数据库执行,但是数据库SQL执行顺序与代码中不同,先增再删了。
网上查询问题原因:
Hibernate 在实际执行SQL语句时并没有按照代码的顺序执行,而是按照 INSERT, UPDATE, DELETE的顺序执行的 原因是Hibernate 为了性能优化,不会直接将SQL语句提交给数据库,而是先放在缓存中,等commit的时候一起提交,利用batch操作提高数据库的性能,而这就导致了SQL的执行顺序与实际的代码顺序不一致,直接导致了代码抛出异常 |
原文地址:https://cloud.tencent.com/developer/article/1603391
解决办法:
在delete后增加一个flush操作,增加该操作不会影响@Transactional事务控制。
personDao.delete(t);
personDao.flush();
personDao.save(newT)
flush
操作是指强制将当前持久化上下文(Persistence Context)中的所有更改立即同步到数据库中,通常不需要手动调用flush
方法,因为Spring Data JPA会在适当的时机自动执行flush
。