Spring自动打开另一个transactionManager?

时间:2010-12-12 16:52:11

标签: hibernate spring transactions transactionmanager

我有两个数据库,有两组弹簧配置: 较低级别为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不报告任何错误(并且不提交任何内容)!

我错过了什么吗?

1 个答案:

答案 0 :(得分:2)

您可以通过xml - <aop:config>执行此操作(您链接的文档中有一个示例)。它将在对象周围创建两个代理,因此将提交2个事务。这是一个不同的故事,这是一个最佳实践。

另一种选择是调用具有

的新方法(在新类中)
@Transactional(propagation=REQUIRES_NEW, "anotherTransactionManager")