行被其他事务更新或删除(或未保存的值映射不正确)
我有一个在Web服务器上运行的Java项目。 我总是打这个例外。
我读了一些文档,发现悲观的locking(或乐观的,但我读的悲观是更好的)是防止这种exception的最好办法。
但是我找不到任何可以解释如何使用它的明确例子。
我的方法是:
@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 2011-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
通常不推荐使用悲观锁,在数据库方面性能非常高昂。 你提到的问题(代码部分)有一些东西不清楚,比如:
- 如果您的代码正在被多个线程同时访问。
- 你如何创build
session
对象(不知道你是否使用Spring)?
Hibernate Session对象不是线程安全的 。 因此,如果有多个线程访问同一个会话并尝试更新相同的数据库实体,那么您的代码可能最终会出现像这样的错误情况。
所以在这里发生的事情是多个线程试图更新相同的实体,一个线程成功,并且当下一个线程提交数据时,它看到它已经被修改并最终抛出StaleObjectStateException
。
编辑 :
有一种方法可以在Hibernate中使用Pessimistic Locking。 看看这个链接 。 但是这个机制似乎有一些问题。 然而,我发现在Hibernate( HHH-5275 )上发布了一个bug。 bug中提到的场景如下:
两个线程正在读取相同的数据库logging; 其中一个线程应该使用悲观locking,从而阻塞另一个线程。 但是这两个线程都可以读取数据库logging,导致testing失败。
这是非常接近你所面临的。 请尝试这个,如果这不起作用,我能想到的唯一方法是使用本机SQL查询 ,您可以实现悲观lockingPostgreSQL数据库与SELECT FOR UPDATE
查询。
看起来您并没有真正使用从数据库中检索的电子邮件,而是使用了作为参数获取的旧版本。 无论是用于版本控制的行已经改变,之间的版本检索时,当你正在进行更新。
您可能希望您的代码看起来更像:
@Transactional Public void test(String id, String subject){ Email email = getEmailById(id); email.setSubject(subject); updateEmail(email); }
这个exception可能是由于乐观的locking(或者你的代码中的一个错误)造成的。 你可能在不知情的情况下使用它。 而你的伪代码(应该被真正的代码replace才能诊断问题)是错误的。 Hibernate会自动保存所有对连接实体的修改。 您不应该在连接的实体上调用update,merge或saveOrUpdate。 做就是了
Email email = session.get(emailId); email.setSubject(subject);
无需调用更新。 Hibernate将在提交事务之前自动刷新更改。
我知道这是一个古老的问题,但我们中的一些人还在打它,看着天空在stream浪。 这是我面对的一个问题,
我们有一个队列pipe理器,用于轮询数据并提供给处理程序进行处理。 为了避免再次获取相同的事件,队列pipe理器将数据库中的logginglocking为LOCKED状态。
void poll() { record = dao.getLockedEntity(); queue(record); }
这个方法不是事务性的,但是dao.getLockedEntity()
是与'REQUIRED'交易的。
一切顺利,在经过几个月的生产之后,乐观locking例外的失败,
经过大量的debugging和详细的检查,我们可以发现有人已经改变了这样的代码,
**@Transactional(Required, readonly=false)** void poll() { record = dao.getLockedEntity(); queue(record); }
所以logging在dao.getLockedEntity()事务之前被排队(它使用poll方法的同一个事务),并且在poll()方法事务得到的时候对象被处理程序(不同的线程)改变comitted。
我们解决了这个问题,现在看起来不错。
我想分享它,因为乐观lockingexception可能会令人困惑,难以debugging。 有人可能会从我的经验中受益。
问候Lyju
检查数据库中是否存在对象,如果存在,则获取对象并刷新它:
if (getEntityManager().contains(instance)) { getEntityManager().refresh(instance); return instance; }
如果它失败了上面的条件…findDB中的对象与Id,做你需要的操作,在这种情况下,确切的变化将反映。
if (....) { } else if (null != identity) { E dbInstance = (E) getEntityManager().find(instance.getClass(), identity); return dbInstance; }
我的项目有这个问题。
我执行乐观locking后,得到了同样的exception。 我的错误是,我没有删除成为@Version
的领域的@Version
。 由于在java空间中调用了setter,字段的值与DB生成的值不匹配。 所以基本上版本字段不匹配了。 此时对实体进行的任何修改都导致:
org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存的值映射不正确)
我在内存数据库和hibernate中使用H2。
我在我的项目的不同背景下遇到了同样的问题,并且有不同的情况
- object is accessed from various source like (server side and client) - without any interval accessing the same object from a different place
在第一种情况下
当我发出一个服务器卡尔,之前保存该对象他们从js的一个调用,并试图保存和另一个地方,我得到了,js的电话是去两三次(我的事情叫绑定的事情引起的问题)
我解决了
e.preventDefault()
第二种情况,
object.lock()
我有同样的问题,在我的情况下,该问题是丢失和/或不正确等于在实体对象的某些types的字段上的实现。 在提交时,Hibernate检查会话中加载的所有实体,以检查它们是否脏。 如果任何一个实体都是脏的,那么hibernate就会试图保存它们,而不pipe被请求保存操作的实际对象与其他实体没有关系。
如果属性具有关联的org.Hibernate.UserType
则通过比较给定对象的每个属性(使用equals方法)或UserType.equals
来完成实体肮脏。
另一件令我吃惊的事情是,在我的交易中(使用Spring注解@Transactional
),我正在处理一个单一的实体。 Hibernate抱怨一些随机的实体,这个实体被保存了。 我意识到有一个我们在REST控制器级别创build的最外层的事务,所以会话的范围太大,因此所有作为请求处理一部分加载的对象都会被检查为不清楚。
希望这有助于某人,有一天。
谢谢抹布
当我尝试从2个不同的会话更新同一行时,发生此错误。 我在一个浏览器中更新了一个字段,而第二个浏览器已经打开,并且已经将原始对象存储在其会话中。 当我试图从第二个“过时”会话更新时,我得到陈旧的对象错误。 为了纠正这个问题,我在我设置要更新的值之前,从数据库中重新获取我的对象,然后将其保存为正常。
以防万一有人检查这个线程,并有同样的问题,我的…
行被其他事务更新或删除(或未保存的值映射不正确)
我正在使用NHibernate,我收到同样的错误,在创build一个对象…
我手动传递密钥,并且在映射中指定了一个GUID生成器,所以hibernate为我生成同样的确切的错误,所以一旦我删除了GUID,并将字段留空,一切都很好。
这个答案可能不会帮助你,但会帮助像我这样的人,只是你的线程,因为相同的错误
我在我的Grails项目中遇到了同样的问题。 问题是,我覆盖收集字段的getter方法。 这在其他线程中总是返回集合的新版本。
class Entity { List collection List getCollection() { return collection.unique() } }
解决方法是重命名getter方法:
class Entity { List collection List getUniqueCollection() { return collection.unique() } }
为了防止StaleObjectStateException
,在你的hbm
文件中写下面的代码:
<timestamp name="lstUpdTstamp" column="LST_UPD_TSTAMP" source="db"/>
我在我的一个应用程序中遇到了这个问题,现在,我知道这是一个旧的线程,但这里是我的解决scheme; 我想通过查看debugging器中的数据,当Hibernate尝试更新数据库(实际上是在另一个线程中完成的)时,JVM实际上并没有正确加载它,所以我在每个字段中添加了关键字“volatile”的实体。 它有一些性能问题要做,而不是重物抛出周围…
- 使用复合主键和注解映射ManyToMany:
- 在Hibernate中重新挂接分离对象的正确方法是什么?
- 没有Hibernate Session绑定到线程,configuration不允许在这里创build非事务性的
- 我如何从jackson的一个自定义反序列化器中调用默认的反序列化器
- 为什么不使用Spring的OpenEntityManagerInViewFilter
- 春季hibernate – 无法获取当前线程的事务同步会话
- buildSessionFactory()在hibernate 4中被弃用了吗?
- JPA @OneToMany – >父 – 子参考(外键)
- 为什么Hibernate不需要参数构造函数?