最近日志出现一个报错
2021-09-09 22:20:21,483 ERROR [ConsumeMessageThread_16] [middle,,,] [CarAssignFailedHandle.handle] [CarAssignFailedHandle.java:58] - Object of class [com.trip.engine.bean.OrderEntity] with identifier [356202191582900224]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.trip.engine.bean.OrderEntity#356202191582900224]
org.springframework.ObjectOptimisticLockingFailureException: Object of class [com.trip.engine.bean.OrderEntity] with identifier [356202191582900224]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.trip.engine.bean.OrderEntity#356202191582900224]
at org.springframework.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:337) ~[spring-orm-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255) ~[spring-orm-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:178) ~[spring-data-jpa-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
从异常信息上看乐观锁定失败;嵌套异常为org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
排查原因:
jpa并发更新同一实体类引起的(两个线程获取同一行记录,线程一优先提交了事务,版本号一致,更新成功,线程二提交事务时版本不一致便出现此异常)
原因分析:
1.数据库并发导致乐观锁异常
2.存在其他存储过程或者方法锁表,长期没有释放锁,导致报错
解决方案:
1、使用原生SQL更新语句进行更新,缺点是舍弃了jpa的对象管理方式
2、通过悲观锁,使事务顺序执行,缺点是也需要写SQL或者加jpa注解,不够方便
3、通过AOP统一拦截该异常并进行一定次数的重试,缺点是不同业务不同情况处理方式不同
4、不使用jpa乐观锁,考虑其它分布式锁处理,保证数据一致性
项目中实体类使用乐观锁的方式加锁:
@Version
@Column(name = "version")
private Integer version;
@Version注解不需要手动控制,每一次save操作会在原来的基础上+1;如果初始为null,则springdata自动设置其为0;另外@Query中的update,delete操作不会触发springdata的相关代理操作
文章仅作为个人学习整理
这篇博客探讨了在使用JPA时遇到的乐观锁定失败异常,详细分析了异常产生的原因,包括并发更新和数据库锁问题。提出了四种解决策略:使用原生SQL更新、悲观锁、AOP重试机制和分布式锁,并对每种策略的优缺点进行了说明。文中还展示了实体类中使用@Version注解实现乐观锁的例子。
8583

被折叠的 条评论
为什么被折叠?



