对于我的grails项目,我有一个用于大多数类的内存h2数据库,但只是为所有与User相关的类添加了一个持久数据库。在启动时,该应用程序执行多个线程。添加第二个数据源后,我得到了HibernateExceptions。特别,

Illegal attempt to associate a collection with two open sessions; nested exception is org.hibernate.HibernateException 

它们仅在第一个或两个线程中发生,然后其余线程执行而没有问题。这使我相信数据库首先启动时存在某种并发问题。发生错误的代码是:
instance.customer = customerService.retrieveCustomer instance 
instance.name = instance.customer?.name 
 
Instance.withTransaction{ 
    instance.customer.save()  // <-- THIS LINE IS THE PROBLEM 
    instance.save() 
} 

我不知道这是数据库问题,休眠问题还是其他原因。
运行Grails 2.0.4

完整的堆栈跟踪:
| Error 2013-03-20 16:25:30,995 [pool-16-thread-1] ERROR kindlingcustomers.InstanceList  - k_54 Illegal attempt to associate a collection with two open sessions; nested exception is org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions org.springframework.orm.hibernate3.HibernateSystemException: Illegal attempt to associate a collection with two open sessions; nested exception is org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions 
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:683) 
    at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412) 
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411) 
    at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339) 
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.SavePersistentMethod.performSave(SavePersistentMethod.java:56) 
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod.doInvokeInternal(AbstractSavePersistentMethod.java:212) 
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractDynamicPersistentMethod.invoke(AbstractDynamicPersistentMethod.java:63) 
    at org.codehaus.groovy.grails.commons.metaclass.DynamicMethodInvocation$invoke.call(Unknown Source) 
    at org.codehaus.groovy.grails.orm.hibernate.HibernateGormInstanceApi.save(HibernateGormEnhancer.groovy:847) 
    at kindlingcustomers.Customer.save(Customer.groovy) 
    at kindlingcustomers.Customer$save$0.call(Unknown Source) 
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112) 
    at kindlingcustomers.InstanceList$__clinit__closure5_closure8.doCall(InstanceList.groovy:67) 
    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 com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231) 
    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:1047) 
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1110) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877) 
    at groovy.lang.Closure.call(Closure.java:412) 
    at kindlingcustomers.InstanceList$__clinit__closure5_closure8.call(InstanceList.groovy) 
    at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:51) 
    at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:82) 
    at com.sun.proxy.$Proxy30.doInTransaction(Unknown Source) 
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130) 
    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 com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231) 
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSite.invoke(PojoMetaMethodSite.java:189) 
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53) 
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116) 
    at org.grails.datastore.gorm.GormStaticApi.withTransaction(GormStaticApi.groovy:573) 
    at kindlingcustomers.Instance.withTransaction(Instance.groovy) 
    at kindlingcustomers.Instance$withTransaction.call(Unknown Source) 
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116) 
    at kindlingcustomers.InstanceList$__clinit__closure5.doCall(InstanceList.groovy:66) 
    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 com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231) 
    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:1047) 
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1110) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:921) 
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1110) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:877) 
    at groovy.lang.Closure.call(Closure.java:412) 
    at groovy.lang.Closure.call(Closure.java:406) 
    at groovy.lang.Closure.run(Closure.java:490) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) 
    at java.lang.Thread.run(Thread.java:680) 

我的数据源:
environments { 
    development { 
        dataSource { 
            dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', '' 
            url = "jdbc:h2:mem:devDb;MVCC=TRUE" 
        } 
 
        dataSource_users { 
            dbCreate = "update"  
            url = "jdbc:h2:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000" 
        } 
    } 
    test { 
        dataSource { 
            dbCreate = "update" 
            url = "jdbc:h2:mem:testDb;MVCC=TRUE" 
        } 
 
        dataSource_users { 
            dbCreate = "update" 
            url = "jdbc:h2:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000" 
        } 
    } 
    production { 
        dataSource { 
            dbCreate = "create-drop" 
            url = "jdbc:h2:mem;MVCC=TRUE" 
            pooled = true 
            properties { 
               maxActive = -1 
               minEvictableIdleTimeMillis=1800000 
               timeBetweenEvictionRunsMillis=1800000 
               numTestsPerEvictionRun=3 
               testOnBorrow=true 
               testWhileIdle=true 
               testOnReturn=true 
               validationQuery="SELECT 1" 
            } 
        } 
 
        dataSource_users { 
            dbCreate = "update" 
            url = "jdbc:h2:prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000" 
        } 
    } 
} 

请您参考如下方法:

我设法通过相当草率的解决方法来抑制异常。希望它将对其他人有所帮助,但是如果有人对问题有其他解决方案或见解,我很乐意听到。

无论如何,您需要在适当的时候调用merge()而不是save()。我不知道如何确定是否在多个 session 中引用了一个实例,因此我只是将每个保存都包装在一个try-catch块中,如果有异常,则调用merge()。这不是最漂亮的解决方案,但它可以工作。

def customerService = AH.application.mainContext.customerService 
instance.customer = customerService.retrieveCustomer instance 
instance.name = instance.customer?.name ?: instance.domain?.tokenize('.')[0].capitalize() ?: '' 
 
Instance.withTransaction{ 
    try{ instance.customer.save() }  
    catch (Exception e) { instance.customer.merge() } 
 
    try { instance.save() }  
    catch (Exception e) { instance.merge() }                     
} 


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!