2つのデータベースがあり、2セットのスプリング構成があります。下位レベルはCORE
db、上位レベルはAPP
dbです。
各dbには、persistenceUnit、entityManagerFactory、transactionManagerがあり、「entityManagerFactoryApp」、「transactionManagerCore」などのdb名が追加されています。
今、私はServiceクラスを持っており、いくつかのDAOをAPPでラップし、いくつかを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アクションはコミットされません。しかし、2つのtxManagerを同時に有効にすることはできません(方法はありますか?)。
だから、私は私のサービスクラスを変更します:
@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を自動的に開き、txを開始/終了する方法はありますか?
PS:私はこれに気づきました:10.5.6.2 @Transactionalを持つ複数のトランザクションマネージャー、しかしそれは私の要件を満たしていないようです:ONE
メソッドで別のtxManagerを開きます。
環境:春-3.0.5、休止状態-3.6.0、JPA2
- 更新しました -
新しい@Transactional(value = "txMgrName")メソッドを呼び出すように指示してくれた@Bozhoに感謝します。試しましたが、失敗しました。
これが私のサービスコードです:
@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
しかし、それでも失敗しました!実際、springはsomeCoreMethod()の@Transactionalアノテーションをスキップしていることがわかりました。
@Transactional(value = " non-existence-txManager-name ")に間違ったtxManagerで注釈を付けることもでき、Springはエラーを報告しません(そして何もコミットしません)!
私は何かを逃しましたか?