Spring - 是否可以在同一个应用程序中使用多个事务管理器?

74

我刚开始学习Spring,想知道是否可以在同一个应用程序中使用多个事务管理器?

我有两个数据访问层 - 一个用于每个数据库。我想知道如何为一个层使用一个事务管理器,为另一个层使用不同的事务管理器。我目前不需要跨两个数据库执行事务。但是我确实需要在每个数据库上单独执行事务。我创建了一张图片来帮助概述我的问题:

alt text

这是我的应用程序上下文配置:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <context:component-scan base-package="cheetah.repositories" />
    <tx:annotation-driven />

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="accounts" />
    </bean>

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

</beans>

这里有一个使用此配置的示例:
@Repository
public class JpaAccountRepository implements AccountRepository {

    @PersistenceContext(unitName = "cheetahAccounts")
    private EntityManager accountManager;

    @Override
    @Transactional
    public Account findById(long id) {

        Account account = accountManager.find(Account.class, id);
        return account;
    }
}

所以对于账户存储库,我想使用一个实体管理器工厂,并将持久性单元设置为帐户。然而,对于我的BusinessData存储库,我想使用一个不同的持久性单元的实体管理器工厂。由于我只能定义一个事务管理器bean,我该如何为不同的存储库使用不同的事务管理器?
谢谢任何帮助。
2个回答

98

在使用 @Transactional 注释时,可以通过添加一个设置为 Bean 名称或限定符的属性来 指定要使用的事务管理器。例如,如果您的应用程序上下文定义了多个带有限定符的事务管理器:

<bean id="transactionManager1"
    class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory1" />
    <qualifier value="account"/>
</bean>

<bean id="transactionManager2"
    class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory2" />
    <qualifier value="businessData"/>
</bean>

你可以使用qualifier来指定要使用的事务管理器:

public class TransactionalService {

    @Transactional("account")
    public void setSomethingInAccount() { ... }

    @Transactional("businessData")
    public void doSomethingInBusinessData() { ... }
}

如果有一种方法可以从数据库中读取数据,而不需要使用@Transactional注释进行数据库读取,那该怎么办? - ziggy
3
感谢您的回答!但是您遗漏了<tx:annotation-driven/>这部分内容。 - Dozer
3
如果@Transactional注解没有标明要使用哪个事务管理器,会发生什么? - http8086

5

这个Spring Jira条目讨论了这个问题:

https://jira.spring.io/browse/SPR-3955

如果您没有使用两阶段提交,那么每个连接可能只需要一个事务管理器。您只需要创建两个事务管理器,并将它们注入到适当的连接中。

但是我必须问一个问题:为什么您认为需要两个事务管理器?您可以拥有多个数据库连接。使用这些连接的DAO应该由不同的服务实例化,并且每个服务可以使用自己的事务设置进行注释。一个管理器可以同时容纳两者。为什么您认为需要两个呢?


24
我认为我需要两个事务管理器,因为事务管理器指定实体管理器工厂,而实体管理器工厂则指定要使用的持久化单元。 - Brian DiCasa
1
你能举出任何例子,其中一个事务管理器可以处理具有自己数据源的多个数据库中的事务吗? - saran3h
例子?那就是事务管理器的工作方式。它们管理涉及多个数据库的两阶段提交。 - duffymo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接