首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多个数据源导致HibernateException?

多个数据源导致HibernateException?
EN

Stack Overflow用户
提问于 2013-03-21 04:50:58
回答 2查看 1.7K关注 0票数 2

对于我的grails项目,我的大多数类都有一个内存中的h2数据库,但只是为所有与用户相关的类添加了一个持久数据库。在启动时,应用程序会执行几个线程。在添加第二个数据源之后,我得到了HibernateExceptions。具体来说,

代码语言:javascript
复制
Illegal attempt to associate a collection with two open sessions; nested exception is org.hibernate.HibernateException

它们只在第一个或两个线程中发生,然后其余的线程执行时不会出现问题。这让我相信这是数据库第一次启动时的某种并发问题。发生错误的代码是:

代码语言:javascript
复制
instance.customer = customerService.retrieveCustomer instance
instance.name = instance.customer?.name

Instance.withTransaction{
    instance.customer.save()  // <-- THIS LINE IS THE PROBLEM
    instance.save()
}

我不知道这是数据库问题、hibernate问题还是其他问题。运行Grails 2.0.4

完整的堆栈跟踪:

代码语言:javascript
复制
| 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)

我的数据源:

代码语言:javascript
复制
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"
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-26 01:29:29

我设法用一个相当草率的变通方法抑制了异常。希望它能帮助其他人,但如果有人有其他解决方案或对这个问题有任何见解,我很乐意听到。

无论如何,您希望在适当的时候调用merge()而不是save()。我不知道如何确定一个实例是否跨多个会话被引用,所以我只是将每个存储都包装在try-catch块中,然后在出现异常时调用merge()。这不是最漂亮的解决方案,但它是有效的。

代码语言:javascript
复制
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() }                    
}
票数 1
EN

Stack Overflow用户

发布于 2013-03-26 02:32:15

在Hibernate中,每个PersistedCollection ( Hibernate为任何集合关系设置的包装类)都只与一个Session实例相关联。这是Hibernate确保维护实例标识的Session级别保证的工作的一部分。

您得到的错误指示您在一个Session中加载了一个具有集合的实体,然后尝试在另一个Session中对其执行.save()操作。这可能不起作用,除非您首先采取步骤将该实体与另一个Session相关联,这可以通过调用otherSession.merge(entity)来完成。这就是你的变通方法“有效”的原因。

您应该看看Hibernate文档的this section,它处理从一个数据源到另一个数据源的复制。不过,我不确定replicate在Ruby/Grails中是否可用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15534462

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档