Hibernate 防止Grails中的过时状态错误

Hibernate 防止Grails中的过时状态错误,hibernate,grails,groovy,Hibernate,Grails,Groovy,我遇到了一个由一堆线程并发访问的方法的问题。该场景是线程A遍历一个列表,创建并保存一个域对象。线程B在线程A仍在迭代时调用相同的方法,尝试访问线程A创建的域对象,并引发StaleStateException 举例说明: def populateStudents(listOfStudents) { listOfStudents.each { Student student -> def schoolName = student.schoolName def s

我遇到了一个由一堆线程并发访问的方法的问题。该场景是线程A遍历一个列表,创建并保存一个域对象。线程B在线程A仍在迭代时调用相同的方法,尝试访问线程A创建的域对象,并引发StaleStateException

举例说明:

def populateStudents(listOfStudents) {

   listOfStudents.each { Student student ->
      def schoolName = student.schoolName
      def school = School.findByName(schoolName) ?: new School(name: schoolName).save(flush:true)

      student.addToSchools(school)

      // So Thread A creates a new School domain object and continues to iterate.
      // Thread B comes along and finds the domain created by Thread A.
      // However, it appears that the StaleStateException is thrown when Thread B tries to addToSchools

   }

}
以下是堆栈:

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.app.School#60]
    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.codehaus.groovy.grails.orm.hibernate.events.PatchedDefaultFlushEventListener.performExecutions(PatchedDefaultFlushEventListener.java:46)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
    at org.springframework.orm.hibernate3.HibernateTemplate$28.doInHibernate(HibernateTemplate.java:883)
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
    at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
    at org.springframework.orm.hibernate3.HibernateTemplate.flush(HibernateTemplate.java:881)
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.MergePersistentMethod$1.doInHibernate(MergePersistentMethod.java:60)
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
    at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339)
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.MergePersistentMethod.performSave(MergePersistentMethod.java:54)
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod.doInvokeInternal(AbstractSavePersistentMethod.java:179)
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractDynamicPersistentMethod.invoke(AbstractDynamicPersistentMethod.java:59)
    at sun.reflect.GeneratedMethodAccessor23965.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSite.invoke(PojoMetaMethodSite.java:188)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:132)
    at org.codehaus.groovy.grails.plugins.orm.hibernate.HibernatePluginSupport$_addBasicPersistenceMethods_closure73.doCall(HibernatePluginSupport.groovy:814)
    at sun.reflect.GeneratedMethodAccessor845.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:80)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoMetaMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:307)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at com.app.TransactionService$_populateStudents_closure3.doCall(TransactionService.groovy:96)
    at sun.reflect.GeneratedMethodAccessor24059.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1070)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)
    at groovy.lang.Closure.call(Closure.java:282)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.eachWithIndex(DefaultGroovyMethods.java:1213)
    at org.codehaus.groovy.runtime.dgm$150.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:270)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at com.app.TransactionService.populateStudents(TransactionService.groovy:49)
    at com.app.TransactionService$$FastClassByCGLIB$$1b289e99.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.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)
    at com.app.TransactionService$$EnhancerByCGLIB$$8986440c.populateStudents(<generated>)


INFO UpdateController - Object of class [com.app.School] with identifier [60]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.app.School#60]
org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存的值映射不正确):[com.app.School#60]
位于org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1792)
位于org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2435)
位于org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)
位于org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)
位于org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)
位于org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
位于org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
位于org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
位于org.codehaus.groovy.grails.orm.hibernate.events.PatchedDefaultFlushEventListener.performExecutions(PatchedDefaultFlushEventListener.java:46)
位于org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
位于org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
位于org.springframework.orm.hibernate3.HibernateTemplate$28.doInHibernate(HibernateTemplate.java:883)
位于org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
位于org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
位于org.springframework.orm.hibernate3.HibernateTemplate.flush(HibernateTemplate.java:881)
位于org.codehaus.groovy.grails.orm.hibernate.metaclass.MergePersistentMethod$1.doInHibernate(MergePersistentMethod.java:60)
位于org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
位于org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339)
位于org.codehaus.groovy.grails.orm.hibernate.metaclass.MergePersistentMethod.performSave(MergePersistentMethod.java:54)
位于org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod.doInvokeInternal(AbstractSavePersistentMethod.java:179)
位于org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractDynamicPersistentMethod.invoke(AbstractDynamicPersistentMethod.java:59)
位于sun.reflect.GeneratedMethodAccessor23965.invoke(未知源)
在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)中
位于java.lang.reflect.Method.invoke(Method.java:616)
位于org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSite.invoke(PojoMetaMethodSite.java:188)
位于org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
位于org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:132)
在org.codehaus.groovy.grails.plugins.orm.hibernate.HibernatePluginSupport$\u addBasicPersistenceMethods\u closure73.doCall(HibernatePluginSupport.groovy:814)
位于sun.reflect.GeneratedMethodAccessor845.invoke(未知源)
在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)中
位于java.lang.reflect.Method.invoke(Method.java:616)
位于org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
位于org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:80)
位于org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$pogometamethodsiteNounwrapnocerc.invoke(PogoMetaMethodSite.java:307)
位于org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
位于org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
在com.app.TransactionService$\u populateStudents\u closure3.doCall(TransactionService.groovy:96)
位于sun.reflect.GeneratedMethodAccessor24059.invoke(未知源)
在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)中
位于java.lang.reflect.Method.invoke(Method.java:616)
位于org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
位于groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
位于groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
位于groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1070)
位于groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)
调用(Closure.java:282)
位于org.codehaus.groovy.runtime.DefaultGroovyMethods.eachWithIndex(DefaultGroovyMethods.java:1213)
位于org.codehaus.groovy.runtime.dgm$150.invoke(未知源)
位于org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$pojoMetamethodSiteNounwrapnocerc.invoke(PojoMetaMethodSite.java:270)
位于org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
位于org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
在com.app.TransactionService.populateStudents上(TransactionService.groovy:49)
在com.app.TransactionService$$FastClassByCGLIB$$1b289e99.invoke()上
net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
位于org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688)
在org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:150)上
位于org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
位于org.springframework.aop.frame
def school = School.findByName(schoolName, [lock: true]) ?: new School(name: schoolName).save(flush:true)