该行已由另一个事务更新或删除(或未保存的值映射不正确)

我阅读了一些文档,发现悲观锁定(或乐观,但我阅读悲观更好)是防止此异常的最佳方法。

但是我找不到任何清晰的示例来说明如何使用它。

我的方法是这样的:

@Transactional

Public void test(Email email, String Subject){

getEmailById(String id);

email.setSubject(Subject);

updateEmail(email);

}

而:

  • Email 是一个hibernate类(它将是数据库中的一个表)
  • getEmailById(String id)是返回的函数email(此方法未使用注释@Transctional
  • updateEmail(email):是一种更新电子邮件的方法。

注:我使用Hibernate进行保存,更新和等(例如:session.getcurrentSession.save(email)

例外:

ERROR 2019-12-21 15:29:24,910 Could not synchronize database state with session [myScheduler-1]

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [email#21]

at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1792)

at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2435)

at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)

at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)

at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)

at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)

at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)

at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)

at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)

at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)

at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)

at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)

at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)

at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)

at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)

at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)

at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)

at $Proxy130.generateEmail(Unknown Source)

at com.admtel.appserver.tasks.EmailSender.run(EmailNotificationSender.java:33)

at com.admtel.appserver.tasks.EmailSender$$FastClassByCGLIB$$ea0d4fc2.invoke(<generated>)

at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)

at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)

at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)

at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:50)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)

at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:50)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)

at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)

at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)

at com.admtel.appserver.tasks.EmailNotificationSender$$EnhancerByCGLIB$$33eb7303.run(<generated>)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:273)

at org.springframework.scheduling.support.MethodInvokingRunnable.run(MethodInvokingRunnable.java:65)

at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:51)

at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)

at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)

at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:180)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:204)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

at java.lang.Thread.run(Thread.java:680)

ERROR 2011-12-21 15:29:24,915 [ exception thrown < EmailNotificationSender.run() > exception message Object of class [Email] with identifier [211]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Email#21] with params ] [myScheduler-1]

org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Object of class [Email] with identifier [21]: optimistic locking failed; nested exception is

回答:

常不建议使用悲观锁定,就数据库方面的性能而言,这是非常昂贵的。你提到的问题(代码部分)尚不清楚,例如:

  • 如果你的代码同时被多个线程访问。
  • 你如何创建session对象(不确定是否使用Spring)?

    hibernate会话对象不是线程安全的。因此,如果有多个线程访问同一个会话并尝试更新同一个数据库实体,则你的代码可能最终会出现这种错误情况。

因此,这里发生的事情是,有多个线程尝试更新同一实体,一个线程成功,当下一个线程提交数据时,它看到其已被修改并最终抛出StaleObjectStateException

编辑:

在Hibernate中有一种使用Pessimistic Locking 的方法。但是这种机制似乎存在一些问题。但是,我偶然发现了一个hibernate状态的错误(HHH-5275)。该错误中提到的情况如下:

两个线程正在读取同一数据库记录。这些线程中的一个应使用悲观锁定,从而阻止另一个线程。但是两个线程都可以读取数据库记录,从而导致测试失败。

这与你所面临的非常接近。如果这不起作用,请尝试此操作,我能想到的唯一方法是使用本机SQL查询,你可以在其中使用查询在postgres数据库中实现悲观锁定SELECT FOR UPDATE。

以上是 该行已由另一个事务更新或删除(或未保存的值映射不正确) 的全部内容, 来源链接: utcz.com/qa/420989.html

回到顶部