3.4. 使用 Spring Boot 事务客户端

Spring Framework(和 Spring Boot)主要目标之一是使 JavaEE API 更易于使用。所有主要的 JavaEE vanilla API 在 Spring Framework(Spring Boot)中都有它们的一部分。这些不是给定 API 的替代方案或替代,而是打包程序会添加更多配置选项或更一致的用法,例如,处理异常。

下表将给定的 JavaEE API 与其 Spring 相关的接口匹配:

JavaEE APISpring 工具程序配置使用

JDBC

org.springframework.jdbc.core.JdbcTemplate

javax.sql.DataSource

JMS

org.springframework.jms.core.JmsTemplate

javax.jms.ConnectionFactory

JTA

org.springframework.transaction.support.TransactionTemplate

org.springframework.transaction.PlatformTransactionManager

JdbcTemplateJmsTemplate 分别使用 javax.sql.DataSourcejavax.jms.ConnectionFactory。但 TransactionTemplate 使用 PlatformTransactionManager 的 Spring 接口。在这里,Spring 不只是 改进 JavaEE,而是将 JavaEE 客户端 API 替换为其自身的。

Spring 将 javax.transaction.UserTransaction 视为一个对于实际情况来说非常简单的接口。另外,因为 javax.transaction.UserTransaction 无法区分本地、单一资源事务和全球多资源事务,因此 org.springframework.transaction.transaction.PlatformTransactionManager 赋予开发人员更具自由度。

以下是 Spring Boot 的规范 API 用法:

// Create or get from ApplicationContext or injected with @Inject/@Autowired.
JmsTemplate jms = new JmsTemplate(...);
JdbcTemplate jdbc = new JdbcTemplate(...);
TransactionTemplate tx = new TransactionTemplate(...);

tx.execute((status) -> {
    // Perform JMS operations within transaction.
    jms.execute((SessionCallback<Object>)(session) -> {
        // Perform operations on JMS session
        return ...;
    });
    // Perform JDBC operations within transaction.
    jdbc.execute((ConnectionCallback<Object>)(connection) -> {
        // Perform operations on JDBC connection.
        return ...;
    });
    return ...;
});

在上例中,所有三种类型的 模板都 只是实例化,但它们也可以从 Spring 应用的 Context 获取,或使用 @Autowired 注解注入。

3.4.1. 使用 Spring PlatformTransactionManager 接口

如前文中所述,javax.transaction.UserTransaction 通常来自 JavaEE 应用中的 JNDI。但是 Spring 会为很多场景提供这个界面的显式实现。您不需要完整的 JTA 情景,有时应用只需要访问单个资源,如 JDBC。

通常, org.springframework.transaction.PlatformTransactionManager 是 Spring 事务客户端 API,提供经典的事务客户端操作: 开始提交和 回滚换句话说,此接口提供了在运行时控制事务的基本方法。

注意

任何事务系统的另一个关键方面是实施事务资源的 API。但是,事务资源通常由底层数据库实施,因此交易编程的此类方面很少是应用程序编程的关注。

3.4.1.1. PlatformTransactionManager 接口的定义

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

    void commit(TransactionStatus status) throws TransactionException;

    void rollback(TransactionStatus status) throws TransactionException;
}

3.4.1.2. 关于 TransactionDefinition 接口

您可以使用 TransactionDefinition 接口指定新创建的事务的特征。您可以指定新事务的隔离级别和传播策略。详情请查看 第 9.4 节 “事务传播策略”

3.4.1.3. TransactionStatus 接口的定义

您可以使用 TransactionStatus 接口来检查当前事务的状态,即与当前线程关联的事务,并为当前线程标记当前的事务进行回滚。这是接口定义:

public interface TransactionStatus extends SavepointManager, Flushable {

    boolean isNewTransaction();

    boolean hasSavepoint();

    void setRollbackOnly();

    boolean isRollbackOnly();

    void flush();

    boolean isCompleted();
}

3.4.1.4. 由 PlatformTransactionManager 接口定义的方法

PlatformTransactionManager 接口定义以下方法:

getTransaction()
创建一个新的事务,并通过传递一个 定义新事务 的特性来将其与当前线程相关联。这与许多其他事务客户端 API 的 start () 方法类似。
commit()
提交当前的事务,这样对注册的资源的所有待处理的更改都是永久的。
rollback()
回滚当前的事务,这会撤消对注册的资源的所有待处理更改。

3.4.2. 使用事务管理器的步骤

通常,您不会直接使用 PlatformTransactionManager 接口。在 Apache Camel 中,您通常使用事务管理器,如下所示:

  1. 创建事务管理器实例。Spring 中有几种不同的实现,请参阅 第 3.4 节 “使用 Spring Boot 事务客户端”
  2. 将事务管理器实例传递到 Apache Camel 组件或路由中的 transacted() DSL 命令。然后,事务组件或 transacted() 命令负责分离事务。详情请查看 第 9 章 编写使用事务的 Camel 应用程序

3.4.3. 关于 Spring PlatformTransactionManager 实现

本节概述了 Spring Framework 提供的事务管理器实现。该实施分为两类:本地事务管理器和全球交易经理。

从 Camel 开始:

  • camel-jms 组件使用的 org.apache.camel.component.JmsConfiguration 对象需要 org.springframework.transaction.transaction.PlatformTransactionManager 接口的实例。
  • org.apache.camel.component.sql.SqlComponent 在内部使用 org.springframework.jdbc.core.JdbcTemplate 类,此 JDBC 模板也与 org.springframework.transaction.transaction.transaction.PlatformTransactionManager 集成。

如您所见,您必须 有一些 实现这个接口。根据具体情况,您可以配置所需的平台事务管理器。

3.4.3.1. Local PlatformTransactionManager 实现

以下列表总结了 Spring Framework 提供的本地事务管理器实现。这些事务管理器只支持单个资源。

org.springframework.jms.connection.JmsTransactionManager
此事务管理器实施能够管理 单个 JMS 资源。您可以连接到任意数量的队列或主题,但前提是它们属于同一基础 JMS 消息传递产品实例。此外,您也无法在事务中列出其他类型的资源。
org.springframework.jdbc.datasource.DataSourceTransactionManager
此事务管理器实施能够管理 单个 JDBC 数据库资源。您可以更新任意数量的不同数据库表,但前提是 它们属于同一基础数据库实例。
org.springframework.orm.jpa.JpaTransactionManager
此事务管理器实施能够管理 Java Persistence API(JPA)资源。但是,无法同时将其他类型的资源列于事务中。
org.springframework.orm.hibernate5.HibernateTransactionManager
此事务管理器实施能够管理 Hibernate 资源。但是,无法同时将其他类型的资源列于事务中。此外,JPA API 比原生 Hibernate API 更首选。

另外,还有其他不常使用的、不常使用的、平台 可靠性管理器的 实现。

3.4.3.2. Global PlatformTransactionManager 实现

Spring Framework 提供了一个全局事务管理器实施,用于在 OSGi 运行时使用。org.springframework.transaction.jta.JtaTransactionManager 支持对事务中的多个资源的操作。这个事务管理器支持 XA 事务 API,并可在事务中放入多个资源。要使用此事务管理器,您必须将应用程序部署到 OSGi 容器或 JavaEE 服务器中。

虽然 PlatformTransactionManager 的单资源实施是实际的 实现,但JtaTransactionManager 更加适用于标准 javax.transaction.TransactionManager 的实际实现。

因此,您可以在可以访问的环境中运行 PlatformTransactionManagerJtaTransactionManager 实施(通过 JNDI 或 CDI)已经配置了 javax.transaction.TransactionManager 且通常是 javax.transaction.UserTransaction.通常,这两个接口都由单个对象/服务实施。

以下是配置/使用 JtaTransactionManager 的示例:

InitialContext context = new InitialContext();
UserTransaction ut = (UserTransaction) context.lookup("java:comp/UserTransaction");
TransactionManager tm = (TransactionManager) context.lookup("java:/TransactionManager");

JtaTransactionManager jta = new JtaTransactionManager();
jta.setUserTransaction(ut);
jta.setTransactionManager(tm);

TransactionTemplate jtaTx = new TransactionTemplate(jta);

jtaTx.execute((status) -> {
    // Perform resource access in the context of global transaction.
    return ...;
});

在上例中,JTA 对象(UserTransactionTransactionManager)的实际实例来自 JNDI。在 OSGi 中,它们也可以从 OSGi 服务注册表获得。