我有两个数据库,有两组弹簧配置:下层是CORE
db,上层是APP
db。
每个 db 都有它的 persistenceUnit 、 entityManagerFactory 、 transactionManager ,并附加了 db 名称,例如 "entityManagerFactoryApp" 、 "transactionManagerCore" ...
现在,我有一个 Service 类,在 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 操作都不会被提交。但是我不能同时启用两个 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(s) 并开始/结束 tx?
PS:我注意到这一点:10.5.6.2 Multiple Transaction Managers with @Transactional,但似乎不符合我的要求:在ONE
方法中打开另一个 txManager。
环境:spring-3.0.5,hibernate-3.6.0,JPA2
- 更新 -
感谢@Bozho 告诉我调用一个新的@Transactional(value="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
但是还是失败了!事实上,我发现spring跳过了someCoreMethod()中的@Transactional注解。
我什至可以用 WRONG txManager 注释 @Transactional(value=" non-existence-txManager-name ") ,并且 Spring 不会报告任何错误(并且什么也不提交)!
我错过了什么吗?