解决升级spring boot 3.4.x 导致Row was updated or deleted by another transaction merge无法插入问题

问题描述

今天将项目中spring boot版本升级到3.3.4 后发现原来entityManager.merge()方法抛出异常

[2025-04-21 11:27:55] [1]-[xx.core.SystemOutPrint]-[INFO] Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [xx.modules.org.models.Department#0000000000000000000001]
[2025-04-21 11:27:55] [1]-[xx.core.SystemOutPrint]-[INFO] at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:426)
[2025-04-21 11:27:55] [1]-[xx.core.SystemOutPrint]-[INFO] at org.hibernate.event.internal.DefaultMergeEventListener.merge(DefaultMergeEventListener.java:214)
[2025-04-21 11:27:55] [1]-[xx.core.SystemOutPrint]-[INFO] at org.hibernate.event.internal.DefaultMergeEventListener.doMerge(DefaultMergeEventListener.java:152)
[2025-04-21 11:27:55] [1]-[xx.core.SystemOutPrint]-[INFO] at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:136)
[2025-04-21 11:27:55] [1]-[xx.core.SystemOutPrint]-[INFO] at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:89)
[2025-04-21 11:27:55] [1]-[xx.core.SystemOutPrint]-[INFO] at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
[2025-04-21 11:27:55] [1]-[xx.core.SystemOutPrint]-[INFO] at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:854)
[2025-04-21 11:27:55] [1]-[xx.core.SystemOutPrint]-[INFO] … 61 more

排查思路

从报错信息中看是多事务提交产生的问题,但是我的代码,是在项目启动时做初始化,应该不存在这个问题。
既然没有解决思路,于是去google错误,经过一番搜索大部分结果都是指向了 @GeneratedValue 主键策略,最后在一篇文章中找到了蛛丝马迹。
搜索结果
大概意思是说hiberante 6.6之后如果是新实体的话必须将主键设置为null才能保存。
随后我将ID设置成了null,果然数据成功保存了。

原因分析

升级spring boot 3.4.x之后,hiberante会升级到6.6,6.6之后的hiberante对merge逻辑进行了修改从之前的主键数据库中不存在就插入新数据改为了主键数据库中不存在就抛出异常,导致了上述问题。

解决方案

解决方案有三个方向:
1.主键设置null;
2.降低spring boot(hiberante)版本;
3.想办法覆盖hiberante中merge代码逻辑;

1.主键设置null

这个方案是最简单的方案,让hiberante根据主键策略去自动生成,但是项目中有些数据确实是需要手动设置id的,所以该方案并不能解决需求。

2.降低spring boot(hiberante)版本

既然hiberante6.6版本不行,那么换种思路我不用6.6版本到是不是就可以了,由于使用的是spring boot随意降低hiberante版本的话可能会产生问题。使用hiberante6.5的版本对应的是spring boot 3.3.x版本。经测试该版本可行。

3.想办法覆盖hiberante中merge代码逻辑

既然方案2就可以完美解决问题为什么还会有方案3,那就不得不说spring 官方维护了, 3.3版本的社区支持马上就要结束了。后续除非购买企业支持否则是没有维护的,所以就出现了方案三。
spring boot 支持时间
分析hiberante 源码

类 org.hibernate.event.internal.DefaultMergeEventListener 是关于Merge的处理逻辑
6.5的源码

if ( result == null ) {
   
   
		//TODO: we should throw an exception if we really *know* for sure
		//      that this is a detached instance, rather than just assuming
		//throw new StaleObjectStateException(entityName, id);

		// we got here because we assumed that an instance
		// with an assigned id was detached, when it was
		// really persistent
		entityIsTransient( event, clonedIdentifier, copyCache );
}
else {
   
   
	// before cascade!
	copyCache.put( entity, result, true );
	final Object target = targetEntity( event, entity, persister, id, result );
	// cascade first, so that all unsaved objects get their
	// copy created before we actually copy
	cascadeOnMer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lich.me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值