在网上资料说,hibernate有它自己的优化机制,你所有的操作都会在hibernate的SQL队列里面,这个队列就是先处理Insert,然后再处理Delete。执行顺序和我们写的顺序无关。
如果你要保证先执行Delete操作,那么你需要再delete操作后执行flush()操作,提交事务。然后再执行insert()操作。
我原来一开始这样子写的:
commonService.delete(CaseDetail.class,oldCaseDetail.getId());
commonService.save(caseDetail);
前提:casedetail表的case_sequence_number是唯一键
报错:
Duplicate entry 'XM102020042210481' for key 'idx_caseDetail_case_sequence_number'
oldCaseDetail和caseDetail拥有相同的caseNo值为XM102020042210481,
caseNo在数据库里面是唯一约束,索引名字idx_caseDetail_case_sequence_number。
我在想,上面说的应该是delete,insert 等操作是在同一个事务里面,如果不在同一个事务里面的话,那么这样子写
commonService.delete(CaseDetail.class,oldCaseDetail.getId());
commonService.save(caseDetail);
应该是不会报错的,个人觉得,不是同一事务的话,hibernate是不会把sql存在一个sql队列里面的,都是来一个执行一个,做下实验呢:
我把两个操作不放在事务里面执行:
实验结果:当执行到
commonService.delete(Payback.class,1);的时候,数据库的数据就直接被删除了,当然啦,后面的数据是可以正常保存的。
然后再做一个实验:把这两个操作放在同一个事务里面。
实验结果:
当执行到
commonService.delete(Payback.class,1);的时候,数据库的数据还存在,并没有直接删除,因为在事务里面,事务还没有提交。
当执行后面保存代码的时候,就报错了:
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------
怎么解决这个问题呢?
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------
方案一:就像上面第一个例子,不放在同一个事务,就不会存在这种情况。
方案二:在事务里面,执行了delete操作后,就flush()方法提交sql 【建议】
commit()方法里面有调用到session.flush()方法。flush会把sql执行,打印出来,但是这个时候数据库数据不会变,需要commmit后数据才更改。也就是flush()只是提交sql不执行事务。
实验结果:
是可以正常保存后面的数据的。
关于flush的解读:
方案三:如果项目使用到了spring JdbcTemplate的话,可以删除操作使用 jdbctemplate来,因为他不是hibernate的操作,所有不会被那个在SQL操作里面排队,所以就不存在hiberante的规则--》先insert再删除。