Hibernate执行Update SQL但数据库未更新问题求助
问题排查与解决方案
1. 先确认事务有没有真正提交
既然用的是JTA事务,默认是容器管理(CMT),如果批量处理的代码不在有效事务上下文里,或者事务没提交,哪怕Hibernate打了Update日志,数据库也不会落盘:
- 要是在EJB里,检查方法有没有加
@Transactional,或者默认的事务属性是不是REQUIRED(EJB无注解时默认是这个)。 - 要是手动管事务(BMT),必须显式调用
userTransaction.commit(),不然flush只是把SQL发去数据库,事务没提交最后还是会回滚。 - 看看是不是捕获了异常但没抛出——JTA里方法抛未捕获的RuntimeException,容器会自动回滚事务,你得确保异常处理逻辑不会吞掉导致回滚的信号。
2. 修正批量处理的实体操作逻辑
批量处理时,JPA的一级缓存会攒一堆实体,容易出状态同步问题:
- 每处理完10条(一批),调用
entityManager.clear()清空缓存,避免旧实体的状态干扰后续更新。 - 注意merge的顺序:必须先改实体状态,再调用merge。比如先
r.setStatus(SENT),再entityManager.merge(r),反过来的话修改不会被持久化——merge是把当前实体的状态合并到持久化上下文里的实例,顺序错了等于白改。
3. 检查数据源的自动提交配置
JTA数据源必须把autoCommit设为false,不然容器的事务管理会失效,哪怕你调用了flush,数据库也会自动回滚或者不生效。去WildFly的数据源配置里确认一下这个参数。
4. 排查乐观锁冲突
如果你的MessageRecipient实体加了@Version注解,看看Hibernate日志里的Update语句后面是不是显示rows affected: 0——这说明处理过程中版本号被其他线程改了,导致更新没生效。这种情况得处理乐观锁异常,重新拉最新的实体再更新。
5. 控制flush的时机
别在循环里每条都flush,每批处理完flush一次就行。另外可以试试设置flush模式为COMMIT:
entityManager.setFlushMode(FlushModeType.COMMIT); // 处理一批实体 entityManager.flush();
确保在事务提交前完成flush操作。
内容的提问来源于stack exchange,提问作者Spencer Chigananda
相关产品推荐
相关产品推荐

