2010-12-12 57 views
1

我有兩個數據庫,有兩套彈簧配置: 下層是CORE db,上層是APP db。春天要自動打開另一個transactionManager?

每個數據庫都有persistenceUnit,entityManagerFactory的,transactionManager的,具有附加的數據庫名稱, 如「entityManagerFactoryApp」,「transactionManagerCore」 ......

現在,我有一個服務類,包裝在APP一些的DAO ,還有一些在CORE。但我發現我不能承諾CORE的DAO的在我的測試:

這裏是我的服務類:

@Inject private AppDao appDao; 
    @Inject private CoreDao coreDao; 

    @Override 
    @Transactional 
    public void someMethod(foo bar) 
    { 
    appDao.save(...); //success  
    coreDao.save(...); //failed ! 
    } 

而且這是我的測試類:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations={"classpath:app.xml"}) 
@TransactionConfiguration(transactionManager="transactionManagerApp" , defaultRollback=false) 
public class ServiceTest 
{ 
    @Inject private Service service; 

    @Test 
    @Transactional 
    public void testSomeMethod() 
    { 
    service.someMethod(...); 
    } 
} 

我知道我不能犯的原因CORE的DAO,是因爲測試類的@TransactionConfiguration是「transactionManagerApp」,而不是「transactionManagerCore」。 因此,CORE的DAO中的任何CREATE/UPDATE/DELETE操作都不會被提交。但我不能同時啓用兩個txManagers(有什麼辦法?)

所以,我修改我的服務類:

@Inject 
    @Qualifier("entityManagerFactoryCore") 
    private EntityManagerFactory emfCore; 

    @Override 
    @Transactional 
    public void someMethod(foo bar) 
    { 
    appDao.save(...); //success  

    Session session = (Session) EntityManagerFactoryUtils.getTransactionalEntityManager(emfCore).getDelegate(); 
    Transaction tx = session.beginTransaction(); 
    coreDao.save(...); //success 
    tx.commit(); 
    } 

是的,它的作品!但那不是我想要的!因爲它引入了很多冗餘代碼(session,tx,commit ...)。

還有......還有另一種方式,以拆除會話從服務/ EntityManagerFactoryUtils,並將其移動到測試類:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations={"classpath:app.xml"}) 
@TransactionConfiguration(transactionManager="transactionManagerApp" , defaultRollback=false) 
public class ServiceTest 
{ 
    @Inject private Service service; 

    @Inject 
    @Qualifier("entityManagerFactoryCore") 
    private EntityManagerFactory emfCore; 

    @Test 
    @Transactional 
    public void testSomeMethod() 
    { 
    Session session = (Session) EntityManagerFactoryUtils.getTransactionalEntityManager(emfCore).getDelegate(); 
    Transaction tx = session.beginTransaction(); 
    service.someMethod(...); 
    tx.commit(); 
    } 
} 

它也能工作,但它是一樣的難看呢!

現在,我的問題是,有沒有辦法讓Spring自動打開相關的transactionManager(s)並開始/結束tx?

PS:我注意到這個:10.5.6.2 Multiple Transaction Managers with @Transactional,但它似乎不符合我的要求:在ONE方法中打開另一個txManager。

環境:彈簧3.0.5,休眠-3.6.0,JPA2

- 更新 -

感謝@Bozho告訴我打電話給一個新的@Transactional(值= 「txMgrName」 )的方法,我試過了,但還是失敗了:

這裏是我的服務代碼:

@Override 
    @Transactional 
    public void someMethod(foo bar) 
    { 
    appDao.save(...); //success 
    someCoreMethod(); 
    } 

    @Transactional(value="transactionManagerCore" , propagation=Propagation.REQUIRES_NEW) 
    private void someCoreMethod(...) 
    { 
    coreDao.save(...); //failed 
    } 

在core.xml:

<bean id="transactionManagerCore" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactoryCore" /> 
    <qualifier value="transactionManagerCore"/> 
    </bean> 

它仍然失敗,coreDao仍然沒有保存。我想也許是因爲這個方法是私人的,並且不會被Spring截獲。 所以我提取方法進入界面/執行層面:

Service (interface) 
    public void someMethod(foo bar) 
    public void someCoreMethod(...) 

ServiceImpl (class) : unchanged 

但它仍然失敗!實際上,我發現彈簧跳過someCoreMethod()中的@Transactional註釋

我甚至可以使用WRONG txManager註釋@Transactional(value =「non-existence-txManager-name」),並且Spring不報告任何錯誤(並且不提供任何內容)!

我錯過了什麼嗎?

回答

2

您可以通過xml - <aop:config>(在鏈接的文檔中有一個示例)執行此操作。它會在對象周圍創建兩個代理,因此這兩個事務將被提交。這是否是最佳做法是一個不同的故事。

另一種方法是調用一個新的方法(在一個新的類),有

@Transactional(propagation=REQUIRES_NEW, "anotherTransactionManager") 
+0

*這是一個不同的故事,這是否是一個最佳實踐*一個完全不同的故事,是... :-)很好回答btw – 2010-12-12 21:08:36

+0

謝謝,我試過了,但仍然失敗。你可以看看嗎? (我已經更新了我的內容) – smallufo 2010-12-12 23:38:20

+0

@smallufo - 抱歉,忘記提及 - 將該方法放在新班級中。 – Bozho 2010-12-13 06:20:58