我有两个数据库,有两组弹簧配置:
较低级别为CORE
db,较高级别为APP
db。
每个db都有其persistenceUnit,entityManagerFactory,transactionManager,附加了db名称, 例如“entityManagerFactoryApp”,“transactionManagerCore”......
现在,我有一个Service类,在APP中包含一些DAO,在CORE中包含一些DAO。但我发现在测试中我无法提交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 ...)。
并且...还有另一种方法,从Service中删除session / 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
}
核心文件中的:
<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注释。
我甚至可以使用错误的txManager注释@Transactional(value =“非存在-txManager-name ”),而Spring不报告任何错误(并且不提交任何内容)!
我错过了什么吗?
答案 0 :(得分:2)
您可以通过xml - <aop:config>
执行此操作(您链接的文档中有一个示例)。它将在对象周围创建两个代理,因此将提交2个事务。这是一个不同的故事,这是一个最佳实践。
另一种选择是调用具有
的新方法(在新类中)@Transactional(propagation=REQUIRES_NEW, "anotherTransactionManager")