两个事务管理器之间的Spring切换(不需要单个事务行为)

时间:2014-08-29 20:08:08

标签: spring hibernate spring-transactions

要访问2个数据库,我们使用两个不同的事务管理器(每个都有自己的数据源):

第一个交易经理:

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

第二个交易经理:

<bean id="transactionManager2"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory2" />
</bean>

在服务层,我们希望有一个获取id的方法并返回一个DTO。问题是DTO必须填充来自两个数据库的数据。

我们尝试了第一种方法:

  • FooDao:使用sessionFactory(与transactionManager相同)
  • BarDao:使用sessionFactory2(与transactionManager2相同的sessionFactory)

使用以下服务方法:

@Autowired
private FooDao fooDao;

@Autowired
private BarDao barDao;

@Transactional(value="transactionManager", readOnly=true)
public FooBarDto getFoo(int id) {
    Foo foo = fooDao.get(id);

    return createDto(foo);
}

@Transactional(value="transactionManager2", readOnly=true)
public FooBarDto createDto(Foo foo) {
    Bar bar = barDao.get(foo.getId());

    FooBarDto fooBarDto = new FooBarDto();

    fooBarDto.setId(String.valueOf(foo.getId()));
    fooBarDto.setA(String.valueOf(foo.getA()));
    fooBarDto.setB(String.valueOf(foo.getB()));
    fooBarDto.setC(String.valueOf(bar.getC()));
    fooBarDto.setD(String.valueOf(bar.getD()));

    return fooBarDto;
}

但是在这种情况下,我们得到了#34;当前线程没有找到会话&#34; barDao方法中的错误。由于我们不需要对单个事务进行整个操作(并保留当前配置),因此我们不希望使用JTA。

我们尝试配置事务传播(使用Propagation.REQUIRES_NEW),但看起来它只适用于来自同一经理的事务。

我们可以更改这两种方法并从控制器中调用它们(顺序),但我们更愿意调用单个服务方法来完成所有工作。有没有办法实现预期的行为?


非常感谢里卡多·韦吉拉!按照你的建议,现在一切正常。我将createDto方法移动到另一个服务(BarService)并在第一个服务(FooService)上自动装配它:

@Service
public class FooServiceImpl implements FooService {

    @Autowired
    private FooDao fooDao;

    @Autowired
    private BarService barService;

    @Transactional(value="transactionManager", readOnly=true)
    public FooBarDto getFoo(int id) {
        Foo foo = fooDao.get(id);

        return barService.createDto(foo);
    }
}

创建的BarService:

@Service
public class BarServiceImpl implements BarService {

    @Autowired
    private BarDao barDao;

    @Transactional(value="transactionManager2", readOnly=true)
    public FooBarDto createDto(Foo foo) {
        FooBarDto fooBarDto = new FooBarDto();

        if (foo != null) {
            Bar bar = barDao.get(foo.getId());

            fooBarDto.setId(String.valueOf(foo.getId()));
            fooBarDto.setA(String.valueOf(foo.getA()));
            fooBarDto.setB(String.valueOf(foo.getB()));

            if (bar != null) {
                fooBarDto.setC(String.valueOf(bar.getC()));
                fooBarDto.setD(String.valueOf(bar.getD()));
            }
        }

        return fooBarDto;
    }
}

2 个答案:

答案 0 :(得分:1)

您在同一个bean内调用barDao的{​​{1}} bacuse中没有会话,这意味着方法调用不会通过Spring Transacitional代理。

在Spring中,带有注释为createDto的公共方法的bean myBean需要从包含Spring注入@Transactional实例的其他bean调用,因为事务支持已实现使用代理。您需要将myBean方法移动到另一个bean:

createDto

答案 1 :(得分:0)

如果您使用Java 8,您可以创建类:

@Component
class TransactionWrapper {

    @Transactional
    public <T> T doInTransaction(Supplier<T> supplier) {
       return
    }

在事务上下文中调用类内的方法(即私有方法)。