将实体对象从一个会话移动到另一个会话,作为日常批处理过程的一部分



首先,我将描述一些我正在尝试工作的概念项目:

有一个数据库,其中包含两个架构,PROD 和 ARCHIVE,其中包含一些实体表:TestA、TestB、TestC、TestL。两个架构中的表的结构完全相同。

TestA 有- 与TestL(查找表(的多对一关系,- 与测试B的一对多关系,TestB 与 TestC 具有一对多关系。

休眠产品.cfg.xml

<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="connection.datasource">arcTestDs</property>
        <property name="dialect">org.hibernate.dialect.DB2Dialect</property>
        <property name="default_schema">PROD</property>
        <property name="current_session_context_class">jta</property>
        <property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup</property>
        <property name="hibernate.transaction.factory_class">com.imd.tracking.arc_test.dao.LocalJtaTransactionFactory</property>
        <property name="hibernate.default_schema">PROD</property>
        <property name="hibernate.hbm2ddl.auto">validate</property>
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
        <property name="hibernate.c3p0.timeout">1000</property>
        <property name="show_sql">true</property>
        <mapping resource="com/imd/tracking/arc_test/domain/TestADTO.hbm.xml" />
        <mapping resource="com/imd/tracking/arc_test/domain/TestBDTO.hbm.xml" />
        <mapping resource="com/imd/tracking/arc_test/domain/TestCDTO.hbm.xml" />
        <mapping resource="com/imd/tracking/arc_test/domain/TestLDTO.hbm.xml" />
    </session-factory>
</hibernate-configuration>

冬眠弧.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="connection.datasource">arcTestDs</property>
        <property name="dialect">org.hibernate.dialect.DB2Dialect</property>
        <property name="default_schema">ARCHIVE</property>
        <property name="current_session_context_class">jta</property>
        <property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup</property>
        <property name="hibernate.transaction.factory_class">com.imd.tracking.arc_test.dao.LocalJtaTransactionFactory</property>
        <property name="hibernate.default_schema">ARCHIVE</property>
        <property name="hibernate.hbm2ddl.auto">validate</property>
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
        <property name="hibernate.c3p0.timeout">1000</property>
        <property name="show_sql">true</property>
        <mapping resource="com/imd/tracking/arc_test/domain/TestADTO.hbm.xml" />
        <mapping resource="com/imd/tracking/arc_test/domain/TestBDTO.hbm.xml" />
        <mapping resource="com/imd/tracking/arc_test/domain/TestCDTO.hbm.xml" />
        <mapping resource="com/imd/tracking/arc_test/domain/TestLDTO.hbm.xml" />
    </session-factory>
</hibernate-configuration>

TestADTO.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.imd.tracking.arc_test.domain.TestADTO" table="TESTA">
        <id column="IDX" name="idx" type="integer">
            <generator class="identity" />
        </id>
        <property column="C1" generated="never" lazy="false" name="c1"
            type="string" />
        <property column="I1" generated="never" lazy="false" name="i1"
            type="integer" />
        <many-to-one class="com.imd.tracking.arc_test.domain.TestLDTO"
            column="TEXT" fetch="join" name="text" />
        <set cascade="all-delete-orphan" inverse="true" lazy="false" name="bs"
            sort="unsorted">
            <key column="A_IDX" not-null="true" />
            <one-to-many class="com.imd.tracking.arc_test.domain.TestBDTO" />
        </set>
    </class>
</hibernate-mapping>

TestBDTO.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
        <class name="com.imd.tracking.arc_test.domain.TestBDTO" table="TESTB">
        <id name="idx" type="integer" column="IDX"> 
            <generator class="identity"/>
        </id>
        <many-to-one fetch="join" name="a" column="A_IDX" class="com.imd.tracking.arc_test.domain.TestADTO" />
        <property name="i1" type="integer" column="I1"/>
        <property name="i2" type="integer" column="I2"/>
        <set name="cs"  lazy="false" inverse="true" cascade="all-delete-orphan">
            <key column="B_IDX" not-null="true"/>
            <one-to-many class="com.imd.tracking.arc_test.domain.TestCDTO"/>
        </set>
        </class>
</hibernate-mapping>

TestCDTO.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "C://DTDs//hibernate-mapping-3.0.dtd">
<hibernate-mapping>
        <class name="com.imd.tracking.arc_test.domain.TestCDTO" table="TESTC">
        <id name="idx" type="integer" column="IDX"> 
            <generator class="identity"/>
        </id>
        <many-to-one fetch="join" name="b" column="B_IDX" class="com.imd.tracking.arc_test.domain.TestBDTO" />
        <property name="i1" type="integer" column="I1"/>
        <property name="i2" type="integer" column="I2"/>
        </class>
</hibernate-mapping>

TestLDTO.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "C://DTDs//hibernate-mapping-3.0.dtd">
<hibernate-mapping>
        <class name="com.imd.tracking.arc_test.domain.TestLDTO" table="TESTL">
        <id name="idx" type="integer" column="IDX"> 
            <generator class="identity"/>
        </id>
        <property name="text" type="string" >
            <column name="TEXT" sql-type="char(20)"/>
        </property>
        </class>
</hibernate-mapping>

现在,我得到了两个使用数据源和 jta 事务管理器的会话工厂。

在我的初始化代码中,我使用以下代码配置两个会话工厂:

sfProd = (SessionFactory)new Configuration()
    .configure("/hibernate-prod.cfg.xml")
    .setProperty(Environment.DEFAULT_SCHEMA, "PROD")
    .buildSessionFactory();
sfArc = (SessionFactory)new Configuration()
    .configure("/hibernate-arc.cfg.xml")
    .setProperty(Environment.DEFAULT_SCHEMA, "ARCHIVE")
    .buildSessionFactory();

现在,我想通过这样的代码选择一个TestADTO:

    @Transactional
    public void moveTest(int moveId)
    {
        Session s_prod = sfProd.getCurrentSession();
        @SuppressWarnings("unchecked")
        List<TestADTO> res = (s_prod.createCriteria(TestADTO.class)
        .add(Restrictions.idEq(moveId)).list());  
        TestADTO testA = res.get(0);
        // s_prod.evict(testA); // are those lines needed?
        // s_prod.evict(testA.getText());
        Session s_arc = sfArc.getCurrentSession();
        s_arc.save(testA.getText());
        s_arc.save(testA);
        // later: s_prod.delete(testA);
    }

1(如果我只是运行上面的代码,我得到错误

04.02.2016 12:58:03 com.imd.tracking.arc_test.App [main] DEBUG          org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
    at org.hibernate.collection.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:432)
    at org.hibernate.event.def.WrapVisitor.processCollection(WrapVisitor.java:67)
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:124)
    at org.hibernate.event.def.WrapVisitor.processValue(WrapVisitor.java:121)
    at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:78)
    at org.hibernate.event.def.AbstractSaveEventListener.visitCollectionsBeforeSave(AbstractSaveEventListener.java:391)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:296)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
    at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
    at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
    at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
    at com.imd.tracking.arc_test.dao.Dao.moveTest(Dao.java:161)
    at com.imd.tracking.arc_test.dao.Dao$$FastClassByCGLIB$$464493ab.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
    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.imd.tracking.arc_test.dao.Dao$$EnhancerByCGLIB$$dacf9fd6.moveTest(<generated>)
    at com.imd.tracking.arc_test.App.go(App.java:106)
    at com.imd.tracking.arc_test.App.main(App.java:120)

调用s_arc.save(testA.getText());时引发异常

2(如果我用s_prod.evict(testA);s_prod.evict(testA.getText());分离dto,则会出现错误:

org.hibernate.HibernateException: Don't change the reference to a collection with cascade="all-delete-orphan": com.imd.tracking.arc_test.domain.TestADTO.bs
    at org.hibernate.engine.Collections.prepareCollectionForUpdate(Collections.java:248)
    at org.hibernate.engine.Collections.processReachableCollection(Collections.java:207)
    at org.hibernate.event.def.FlushVisitor.processCollection(FlushVisitor.java:60)
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:124)
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:84)
    at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:78)
    at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:165)
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)
    at org.hibernate.transaction.CacheSynchronization.beforeCompletion(CacheSynchronization.java:88)
    at bitronix.tm.BitronixTransaction.fireBeforeCompletionEvent(BitronixTransaction.java:478)
    at bitronix.tm.BitronixTransaction.commit(BitronixTransaction.java:193)
    at bitronix.tm.BitronixTransactionManager.commit(BitronixTransactionManager.java:120)
    at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1009)
    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:374)
    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.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)
    at com.imd.tracking.arc_test.dao.Dao$$EnhancerByCGLIB$$359759b9.moveTest(<generated>)
    at com.imd.tracking.arc_test.App.go(App.java:106)
    at com.imd.tracking.arc_test.App.main(App.java:120)

当离开方法moveTest(int moveId(时,我认为,当事务提交时会抛出异常。

我对实际项目的目标是调用一个像 moveTest(int moveId( 这样的函数来获取 id 列表。这应该在计划每天运行一次的批处理过程中完成。

问:如何将 dtos 从一个会话移动到另一个会话?

PS:真正的 DTO 有更多的关系,所以如果可能的话,我想避免深度复制。

我认为问题是您的实体正在参与另一个会话。无论如何,您可以尝试使用merge()方法代替save()

也许这个链接会对你有所帮助休眠将对象保存到多个会话

最新更新