StaleObjectStateException高频更新 [英] StaleObjectStateException on high frequency updates

查看:131
本文介绍了StaleObjectStateException高频更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们使用Hibernate 3.6.3.Final和MySQL 5.5.8作为Web应用程序。后端在JBoss 6.0.0 Final服务器上运行。大多数情况下,事情工作得很好,但偶尔我们会得到一个StaleObjectStateException。经过一段时间的实验后,我们发现可以通过高频率向后端发送请求来重现它(例如,单击一个按钮,以尽可能快地触发请求)。

据我所知,异常意味着一个域对象从数据库中获取,当Hibernate试图再次保存它时,它注意到另一个事务在此期间改变了它。



然而就我所了解的数据库而言,冲突事务应该被隔离到一定程度,以防止这种行为。我明确地将隔离级别改为SERIALIZABLE,以保证可重复读取,并禁用了Hibernate缓存。这应该防止一个事务看到相同域对象的不同版本的情况。



完整的堆栈跟踪是:

  2011-04-28 20:46:17,865 WARN [com.arjuna.ats.arjuna](WorkerThread#2 [127.0.0.1:57772])ARJUNA-12125 TwoPhaseCoordinator.beComplete -  SynchronizationImple失败0:ffff7f000001:126a:4db9c7b0:74d,org.hibernate.transaction.synchronization.HibernateSynchronizationImpl@481efbaf>:javax.persistence.OptimisticLockException:org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存的值映射不正确):[xxx.modules.domain.entity.User#118] 
在org.hibernate.ejb.AbstractEntityManagerImpl.wrapStaleStateException(AbstractEntityManagerImpl.java:1243)[:3.6.0.Final]
在org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)[:3.6。org.hibernate.ejb.AbstractEntityManagerImpl.java:1166] [:3.6.0.Final]
。 0.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)[:3.6.0.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl $ 3.mapManagedFlushFailure(AbstractEntityManagerImpl .java:1067)[:3.6.0.Final]
在org.hibernate.tran saction.synchronization.CallbackCoordinator.beforeCompletion(CallbackCoordinator.java:122)[:3.6.0.Final]
at org.hibernate.transaction.synchronization.HibernateSynchronizationImpl.beforeCompletion(HibernateSynchronizationImpl.java:51)[:3.6.0 .Final]
at com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.java:97)[:6.0.0.Final]
at com.arjuna.ats .arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:274)[:6.0.0.Final]
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:94)[: 6.0.0.Final]
at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:159)[:6.0.0.Final]
at com.arjuna.ats.internal。 jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1158)[:6.0.0.Final]
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(Base Transaction.java:119)[:6.0.0.Final]
at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75)[:6.0.0.Final]
at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.endTransaction(CMTTxInterceptor.java:82)[:0.0.1]
at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:255 )[:0.0.1]
at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.required(CMTTxInterceptor.java:349)[:0.0.1]
at org.jboss.ejb3.tx2 .impl.CMTTInterceptor.invoke(CMTTxInterceptor.java:209)[:0.0.1]
at org.jboss.ejb3.tx2.aop.CMTTxInterceptorWrapper.invoke(CMTTxInterceptorWrapper.java:52)[:0.0.1]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)[jboss-aop.jar:2.2.1.GA]
at org.jboss.aspects.tx.TxPropagationInterceptor .invoke(TxPropagationInterceptor.java:76)[:1.0.0.GA]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext (MethodInvocation.java:102)[jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.tx.NullInterceptor.invoke(NullInterceptor.java:42)[:1.0.3]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)[jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptorv2。 invoke(Ejb3AuthenticationInterceptorv2.java:182)[:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)[jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:41)[:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
在org.jboss.ejb3.BlockContainerShutdownInterceptor.invoke(BlockContainerShutdownInterceptor.java:67)[:1.7.17]
在org.jboss.aop .joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)[jboss-aop.jar:2.2.1.GA]
在org.jboss.ejb3.core.context.CurrentInvocationContextInterceptor.invoke(CurrentInvocationContextInterceptor.java:47)[:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
在org.jboss.aspects.currentinvocation.CurrentInvocationInterceptor.invoke(CurrentInvocationInterceptor.java:67)[:1.0.1]
在org.jboss .aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)[jboss-aop.jar:2.2.1.GA]
at org.jboss.ejb3.interceptor.EJB3TCCLInterceptor.invoke(EJB3TCCLInterceptor.java:86 )[:1.7.17]
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)[jboss-aop.jar:2.2.1.GA]
at org。 jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:392)[:1.7.17]
at org.jboss.ejb3.session.InvokableContextClassProxyHack._dynamicInvoke(InvokableContextClassProxyHack.java:53)[:1.7.17 ]
在o rg.jboss.aop.Dispatcher.invoke(Dispatcher.java:91)[jboss-aop.jar:2.2.1.GA]
at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java: 82)[:1.0.1.GA]
在org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:898)[:6.0.0.Final]
在org.jboss.remoting。 transport.socket.ServerThread.completeInvocation(ServerThread.java:791)[:6.0.0.Final]
在org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:744)[:6.0 .0.Final]
在org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:586)[:6.0.0.Final]
在org.jboss.remoting.transport .socket.ServerThread.run(ServerThread.java:234)[:6.0.0.Final]
导致:org.hibernate.StaleObjectStateException:行被其他事务更新或删除(或未保存值映射不正确):[xxx.modules.domain.entity.User#118]
org.hibernate.persister.entity.Abstract EntityPersister.check(AbstractEntityPersister.java:1932)[:3.6.0.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2576)[:3.6.0.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2476)[:3.6.0.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java :2803)[:3.6.0.Final]
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:113)[:3.6.0.Final]
at org.hibernate.engine .ActionQueue.execute(ActionQueue.java:273)[:3.6.0.Final]
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)[:3.6.0.Final]
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:185)[:3.6.0.Final]
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) [1:3。 6.0.Final]
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)[:3.6.0.Final]
at org.hibernate.impl.SessionImpl.flush( SessionImpl.java:1216)[:3.6.0.Final]
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)[:3.6.0.Final]
at org。 hibernate.transaction.synchronization.CallbackCoordinator.beforeCompletion(CallbackCoordinator.java:117)[:3.6.0.Final]
... 39 more

任何帮助表示感谢!



在此先感谢
Michael

非常,非常确定您已将TX设置为可序列化?因为这不应该发生在可序列化的事务上。如果两个TX在一个可序列化的事务中读取和修改同一行,那么oracle会抛出一个 ORA-08177



请检查hibernate是否将TX设置为可序列化。



Edit



您可以执行Jonas建议的操作,也可以通过获取底层连接并调用Connection.getIsolationLevel ()。例如

 连接c = session.connection()
int level = c.getIsolationLevel()



编辑2



好的,既然您确认隔离级别的连接是SERIALILIZABLE,你可以检查:
$ b $ ul

  • 这些表使用的是innoDB引擎。

  • 正如Jonas所建议的,在代码处于事务中时,从代码中运行 SELECT @@ tx_isolation; 。它应该返回 SERIALIZABLE 。这是为了检查Connection是否实际传播隔离级别。这有点偏执,但该怎么办...

  • 检查您的代码是否只打开一个事务,并运行该TX中的所有内容。我只是手动测试了SERIALIZABLE隔离级别并且它按预期工作(它阻止任何TX试图读取同一行)。
  • 最后的手段:检查隔离级别SERIALIZABLE在您的MySQL安装。 行。这意味着,如果您有许多TX同时阅读的国家,公司,用户等一些通用表格,它可能会使您的应用程序几乎按顺序运行而不是并行运行。


    We're using Hibernate 3.6.3.Final and MySQL 5.5.8 for a web application. The backend is running on a JBoss 6.0.0 Final server. Most of the time things work really well but occasionally we're getting a StaleObjectStateException. After a while of experimenting we figured out that it can be reproduced by sending requests to the backend with a high frequency (ie. clicking a button which triggers the request as fast as possible).

    As far as I know the exception means that a domain object got fetched from the database and when Hibernate tried to persist it again it noticed that another transaction changed it in the meantime.

    However as far as I understand databases the conflicting transactions should be isolated to an extent which prevents exactly this behavior. I explicitly changed the isolation level to SERIALIZABLE which guarantees repeatable reads and I disabled Hibernate caching. This should prevent the situation where one transaction sees different versions of the same domain object.

    The full stack trace is:

        2011-04-28 20:46:17,865 WARN  [com.arjuna.ats.arjuna] (WorkerThread#2[127.0.0.1:57772]) ARJUNA-12125 TwoPhaseCoordinator.beforeCompletion - failed for SynchronizationImple< 0:ffff7f000001:126a:4db9c7b0:74d, org.hibernate.transaction.synchronization.HibernateSynchronizationImpl@481efbaf >: javax.persistence.OptimisticLockException: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [xxx.modules.domain.entity.User#118]
            at org.hibernate.ejb.AbstractEntityManagerImpl.wrapStaleStateException(AbstractEntityManagerImpl.java:1243) [:3.6.0.Final]
            at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1166) [:3.6.0.Final]
            at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147) [:3.6.0.Final]
            at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153) [:3.6.0.Final]
            at org.hibernate.ejb.AbstractEntityManagerImpl$3.mapManagedFlushFailure(AbstractEntityManagerImpl.java:1067) [:3.6.0.Final]
            at org.hibernate.transaction.synchronization.CallbackCoordinator.beforeCompletion(CallbackCoordinator.java:122) [:3.6.0.Final]
            at org.hibernate.transaction.synchronization.HibernateSynchronizationImpl.beforeCompletion(HibernateSynchronizationImpl.java:51) [:3.6.0.Final]
            at com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.java:97) [:6.0.0.Final]
            at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:274) [:6.0.0.Final]
            at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:94) [:6.0.0.Final]
            at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:159) [:6.0.0.Final]
            at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1158) [:6.0.0.Final]
            at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:119) [:6.0.0.Final]
            at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75) [:6.0.0.Final]
            at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.endTransaction(CMTTxInterceptor.java:82) [:0.0.1]
            at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:255) [:0.0.1]
            at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.required(CMTTxInterceptor.java:349) [:0.0.1]
            at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.invoke(CMTTxInterceptor.java:209) [:0.0.1]
            at org.jboss.ejb3.tx2.aop.CMTTxInterceptorWrapper.invoke(CMTTxInterceptorWrapper.java:52) [:0.0.1]
            at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76) [:1.0.0.GA]
            at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.ejb3.tx.NullInterceptor.invoke(NullInterceptor.java:42) [:1.0.3]
            at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.ejb3.security.Ejb3AuthenticationInterceptorv2.invoke(Ejb3AuthenticationInterceptorv2.java:182) [:1.7.17]
            at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:41) [:1.7.17]
            at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.ejb3.BlockContainerShutdownInterceptor.invoke(BlockContainerShutdownInterceptor.java:67) [:1.7.17]
            at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.ejb3.core.context.CurrentInvocationContextInterceptor.invoke(CurrentInvocationContextInterceptor.java:47) [:1.7.17]
            at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.aspects.currentinvocation.CurrentInvocationInterceptor.invoke(CurrentInvocationInterceptor.java:67) [:1.0.1]
            at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.ejb3.interceptor.EJB3TCCLInterceptor.invoke(EJB3TCCLInterceptor.java:86) [:1.7.17]
            at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:392) [:1.7.17]
            at org.jboss.ejb3.session.InvokableContextClassProxyHack._dynamicInvoke(InvokableContextClassProxyHack.java:53) [:1.7.17]
            at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:91) [jboss-aop.jar:2.2.1.GA]
            at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java:82) [:1.0.1.GA]
            at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:898) [:6.0.0.Final]
            at org.jboss.remoting.transport.socket.ServerThread.completeInvocation(ServerThread.java:791) [:6.0.0.Final]
            at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:744) [:6.0.0.Final]
            at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:586) [:6.0.0.Final]
            at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:234) [:6.0.0.Final]
    Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [xxx.modules.domain.entity.User#118]
            at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1932) [:3.6.0.Final]
            at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2576) [:3.6.0.Final]
            at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2476) [:3.6.0.Final]
            at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2803) [:3.6.0.Final]
            at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:113) [:3.6.0.Final]
            at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273) [:3.6.0.Final]
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265) [:3.6.0.Final]
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:185) [:3.6.0.Final]
            at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) [:3.6.0.Final]
            at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) [:3.6.0.Final]
            at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) [:3.6.0.Final]
            at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383) [:3.6.0.Final]
            at org.hibernate.transaction.synchronization.CallbackCoordinator.beforeCompletion(CallbackCoordinator.java:117) [:3.6.0.Final]
            ... 39 more
    

    Any help is appreciated!

    Thanks in advance Michael

    解决方案

    Are you very, very sure that you've set the TX to serializable? Because that should never happen on a serializable transaction.

    If two TX read and modify the same row in a serializable transaction, then oracle throws an ORA-08177.

    Please check that hibernate is actually setting the TX as serializable.

    Edit

    You can do what Jonas suggested or you can also check it from you application by getting the underlying connection and invoking Connection.getIsolationLevel(). For example

    Connection c = session.connection()
    int level = c.getIsolationLevel()
    

    Edit 2

    Ok, since you confirmed that the isolation level on the Connection is SERIALILIZABLE, could you check:

    • That the tables are using the innoDB engine.
    • As Jonas suggested, run SELECT @@tx_isolation; from your code while it is in the transaction. It should return SERIALIZABLE. This is to check that the Connection is actually propagating the isolation level. It's a bit paranoid, but what to do...
    • Check that your code only opens one transaction, and runs everything in that TX. I just tested the SERIALIZABLE isolation level manually and it works as expected (it blocks any TX trying to read the same row).
    • Last resort: check that the isolation level SERIALIZABLE works on your MySQL installation.

    NOTE: As I mentioned before, MySQL will block any queries trying to read from the same row. That means that if you have some "common tables" such as country, company, user, etc. that many TXs read concurrently, it might make your app run almost sequencially rather than parallelly.

    这篇关于StaleObjectStateException高频更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆