2010-12-12 16 views
1

2つのデータベースがあり、2つのスプリング構成があります。 下位レベルはCORE db、上位レベルはAPP dbです。Springは別のtransactionManagerを自動的に開きますか?

各DBが追加DB名とそのpersistenceUnit、EntityManagerFactoryに、トランザクションマネージャー、このような "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"であるためです。 したがって、COREのDAOのCREATE/UPDATE/DELETEアクションはコミットされません。しかし、私はを同時に2つの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(); 
    } 

はい、それは動作します!しかし、それは私が欲しいものではありません!これは、冗長なコード(セッション、tx、コミット...)の多くを導入するためです。

そして...もう一つの方法は、サービスからセッション/ 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を開いてtxを開始する方法はありますか?

PS:私はこれに気づきました:10.5.6.2 Multiple Transaction Managers with @Transactionalですが、私の要求を満たしていないようです:ONEメソッドで別のtxManagerを開く。

環境:春-3.0.5、休止状態-3.6.0を、JPA2

は - 更新 -

おかげ@Bozho新しい@Transactional(値= "txMgrName" を呼び出すように私に告げるために)方法、私が試したが、それでも失敗しました:core.xmlで

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

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

ここ

は私のサービスコードであります

<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アノテーションをスキップしていることを発見しました。

@Transactional(value = "non-exist-txManager-name")をWRONG txManagerに注釈しても、Springはエラーを報告しません(コミットしません)!

私は何かを見逃しましたか?

答えて

2

これはxml - <aop:config>で行うことができます(リンクしたドキュメントに例があります)。オブジェクトの周りに2つのプロキシが作成されるため、2つのトランザクションがコミットされます。これがベストプラクティスかどうかは、別の話です。

別のオプションは、それが:-) ...はい、*全く別の話これがベストプラクティスであるかどうかを別の話だ*

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

を持っている(新しいクラスの)新しいメソッドを呼び出すことです良い答えbtw –

+0

ありがとう、私は試しましたが、まだ失敗しました。あなたはそれを見てみますか? (私は自分のコンテンツを更新しました) – smallufo

+0

@smallufo - 申し訳ありませんが、言及して忘れました - メソッドを新しいクラスに配置します。 – Bozho

関連する問題