optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was u...
已于 2023-07-04 20:52:16 修改
2019-06-30 04:58:00 阅读量 1.9w

乐观锁失败

optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

出现以上异常,由于乐观锁version没有对上,导致操作数据库失败。

报错日志:

org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [com.ak47.cms.cms.entity.Tree] with identifier [7]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.ak47.cms.cms.entity.Tree#7] at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:298) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:507) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.repository.core.support.MethodInvocationValidator.invoke(MethodInvocationValidator.java:99) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy118.save(Unknown Source) at com.ak47.cms.cms.InitRunner$initTrees$1.invoke(CmsApplication.kt:59) at com.ak47.cms.cms.InitRunner$initTrees$1.invoke(CmsApplication.kt:35) at com.ak47.cms.cms.tree.TreeUtil.visitTree(TreeUtil.kt:14) at com.ak47.cms.cms.tree.TreeUtil.visitTree(TreeUtil.kt:17) at com.ak47.cms.cms.InitRunner.initTrees(CmsApplication.kt:52) at com.ak47.cms.cms.InitRunner.run(CmsApplication.kt:44) at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:790) at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774) at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234) at com.ak47.cms.cms.CmsApplicationKt.main(CmsApplication.kt:151) Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.ak47.cms.cms.entity.Tree#7] at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:322) at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:170) at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69) at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:883) at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:869) at sun.reflect.GeneratedMethodAccessor86.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:304) at com.sun.proxy.$Proxy110.merge(Unknown Source) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:493) at sun.reflect.GeneratedMethodAccessor85.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377) at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:629) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:593) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ... 23 common frames omitted Hibernate: select tree0_.id as id1_3_0_, tree0_.category as category2_3_0_, tree0_.gmt_created as gmt_crea3_3_0_, tree0_.gmt_modified as gmt_modi4_3_0_, tree0_.is_deleted as is_delet5_3_0_, tree0_.name as name6_3_0_, tree0_.parent_id as parent_i7_3_0_, tree0_.version as version8_3_0_ from tree tree0_ where tree0_.id=? 2019-06-30 04:56:20.773 ERROR 7534 --- [ main] com.ak47.cms.cms.CmsApplication : t:{"category":"COUNTRY","deleted":0,"gmtCreated":1561841780770,"gmtModified":1561841780770,"id":8,"name":"深圳","parentId":1,"version":0} 2019-06-30 04:56:20.774 ERROR 7534 --- [ main] com.ak47.cms.cms.CmsApplication : treeRepository.save(t): org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [com.ak47.cms.cms.entity.Tree] with identifier [8]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.ak47.cms.cms.entity.Tree#8] at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:298) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:507) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.repository.core.support.MethodInvocationValidator.invoke(MethodInvocationValidator.java:99) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy118.save(Unknown Source) at com.ak47.cms.cms.InitRunner$initTrees$1.invoke(CmsApplication.kt:59) at com.ak47.cms.cms.InitRunner$initTrees$1.invoke(CmsApplication.kt:35) at com.ak47.cms.cms.tree.TreeUtil.visitTree(TreeUtil.kt:14) at com.ak47.cms.cms.tree.TreeUtil.visitTree(TreeUtil.kt:17) at com.ak47.cms.cms.InitRunner.initTrees(CmsApplication.kt:52) at com.ak47.cms.cms.InitRunner.run(CmsApplication.kt:44) at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:790) at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774) at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234) at com.ak47.cms.cms.CmsApplicationKt.main(CmsApplication.kt:151) Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.ak47.cms.cms.entity.Tree#8] at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:322) at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:170) at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69) at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:883) at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:869) at sun.reflect.GeneratedMethodAccessor86.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:304) at com.sun.proxy.$Proxy110.merge(Unknown Source) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:493) at sun.reflect.GeneratedMethodAccessor85.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377) at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:629) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:593) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ... 23 common frames omitted

如果一个请求方法中,包含两次以上操作该对象表,那么在前面每次操作完数据库之后,需要将操作后的对象返回,然后下次操作时,保证该对象的版本号是最新的。

Optimistic locking means that when you update a row in a database, the database server will keep track of the version number of that row. When you try to update the row again, the database server will compare the version number of the row in your database with the version number of the row on the server. If the version numbers don’t match, then the database server will know that someone else has updated the row since you last updated it, and it will refuse to let you update the row.
乐观锁定意味着当您更新数据库中的行时,数据库服务器将跟踪该行的版本号。当您尝试再次更新该行时,数据库服务器会将数据库中该行的版本号与服务器上该行的版本号进行比较。如果版本号不匹配,则数据库服务器将知道自上次更新该行以来,其他人已更新该行,并且它将拒绝让您更新该行。

This is to prevent conflicts between different users who are trying to update the same row in a database. If optimistic locking wasn’t used, then it would be possible for two users to update the same row at the same time, and the database server wouldn’t know which user’s update to keep.
这是为了防止尝试更新数据库中同一行的不同用户之间的冲突。如果不使用乐观锁定,则两个用户可能会同时更新同一行,并且数据库服务器不知道要保留哪个用户的更新。

The StaleObjectStateException is thrown when the database server detects that the version number of a row has changed since you last updated it. This can happen if someone else has updated the row since you last updated it, or if you have changed the row in memory and haven’t saved it back to the database.
当数据库服务器检测到行的版本号自上次更新以来已更改时,将引发 StaleObjectStateException。如果自上次更新行以来其他人更新了该行,或者您更改了内存中的行但尚未将其保存回数据库,则可能会发生这种情况。

To resolve this exception, you need to either reload the row from the database or save your changes back to the database.
若要解决此异常,需要从数据库重新加载行或将更改保存回数据库。

This error message typically occurs in a concurrent access scenario where multiple transactions are trying to modify the same database record simultaneously. The error message indicates that one of the transactions failed to update the record because it was already modified by another transaction.
此错误消息通常发生在多个事务尝试同时修改同一数据库记录的并发访问方案中。错误消息指示其中一个事务无法更新记录,因为它已被另一个事务修改。

In optimistic locking, each transaction reads a record from the database and keeps track of a version number. When the transaction updates the record, it includes the version number in the update statement. If another transaction updates the same record before the first transaction commits its changes, the version number will be different, and the database will reject the update with the error message you have seen.
在乐观锁定中,每个事务从数据库中读取一条记录并跟踪版本号。当事务更新记录时,它会在更新语句中包含版本号。如果另一个事务在第一个事务提交其更改之前更新了相同的记录,则版本号将不同,并且数据库将拒绝更新并显示您看到的错误消息。

To resolve the issue, you can retry the transaction that encountered the error, or you can implement a different locking strategy, such as pessimistic locking. Pessimistic locking acquires a lock on the record when it is read, preventing other transactions from modifying it until the lock is released.
若要解决此问题,可以重试遇到错误的事务,也可以实现其他锁定策略,例如悲观锁定。悲观锁定在读取记录时获取记录上的锁,防止其他事务修改它,直到释放锁。

Another possible cause of this error is a mapping issue between the Java objects and the database tables. If the mapping is incorrect, Hibernate may not be able to determine the correct version number of the record, leading to the error message. You can check the mapping configuration and ensure that it is correct.
此错误的另一个可能原因是 Java 对象和数据库表之间的映射问题。如果映射不正确,Hibernate可能无法确定记录的正确版本号,从而导致错误消息。您可以检查映射配置并确保其正确。

In any case, it is important to handle concurrency issues carefully in a multi-user application to prevent data inconsistencies and ensure data integrity.
在任何情况下,在多用户应用程序中仔细处理并发问题以防止数据不一致并确保数据完整性非常重要。

原因:就是要修改的实体的version和数据库中的version对不上。 hibernate 就会认为别人已经并发修改了数据。 解决办法:将数据库中的version从前端回传回来。如果version和数据库一致,还是经常出现这个问题,可以考虑使用悲观锁。 乐观锁:给数据加一个版本, 每一操作数据就更新版本,不会上锁,但是在更新的时候你会判断这期间有没有人去更新这个数据 悲观锁:给数据加了一把锁 ,同事务只能一个线程进行操作,使用完了锁释放, 没释放前后面想要操作的人就得排队 ,效率低,但是很安全 2 问题描述 org . hibernate . Stale Object State Exception : Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) org . hibernate . Stale Object State Exception : Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): 这一人异常调试了一天多才整出来,其原因: 主键对应数据库表中的ID字段,其值由oracle sequence生成, 而ti... org . hibernate . Stale Object State Exception : Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.xx.xx:11] 说明操作的对象时应用了乐观锁机制,或者定义pojo时定义了version字段;或者同时对同一对象(同... org .apache.ibatis. exception s.Persistence Exception : ### Error querying database. Cause: o... Caused by: org . hibernate . Stale Object State Exception : Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.xytai.aiinspector.tflow.entity.StepDefPoJo#3145b6b3-89ab-4ba8-a1bf-ba8da50bd3d0] 2. 请求中指定了id, 和version 但是数据库中有这条记录,但是version不正确(和数据库不一致)4. 请求中不指定了id, 和version ,数据库中会新增一条记录,并且version是0。4. service中直接保存:直接调用 Spring 的 saveAndFlush方法保存数据。2. 请求中指定了id, 和version 但是数据库中有这条记录,结果会更新。1. 保存数据 Id 在数据库中是自增长的。 表示在使用乐观锁定机制时,发生了锁定失败的情况。如果事务隔离级别过低,可能导致多个事务能够同时读取相同的数据,并在提交时引发乐观锁定异常。如果应用程序在读取数据后,对数据进行了修改但未及时更新版本信息,可能导致版本信息不同步,从而引发乐观锁定异常。多个事务同时尝试更新相同的数据记录,但其中一个事务已经提交了更新,导致另一个事务的更新失败。如果应用程序使用了缓存,而缓存中的数据与数据库中的数据不同步,可能导致乐观锁定失败。在发生乐观锁定异常时,如果事务回滚并且没有合适的重试机制,可能导致一连串的失败操作。