第 9 章 编写使用事务的 Camel 应用程序


在配置了三个、可用的引用类型后,您可以编写一个应用程序。三种类型的服务有:

  • 一个事务管理器,它是以下接口之一:

    • javax.transaction.UserTransaction
    • javax.transaction.TransactionManager
    • org.springframework.transaction.PlatformTransactionManager
  • 至少有一个 JDBC 数据源实施 javax.sql.DataSource. 接口。通常,有多个数据源。
  • 至少一个实施 javax.jms.ConnectionFactory 接口的 JMS 连接工厂。通常,有多个。

这部分论述了与管理事务、数据源和连接工厂相关的特定于 Camel 的配置。

注意

本节论述了几个与 Spring 相关的概念,如 SpringTransactionPolicySpring XML DSLBlueprint XML DSL 之间存在明显区别,它们是定义 Camel 上下文的 XML 语言。Spring XML DSL 现在在 Fuse 中被弃用。但是,Camel 事务机制仍然在内部使用 Spring 库。

这里的大部分信息都不依赖于所使用的 PlatformTransactionManager 类型。如果 PlatformTransactionManager 是 Narayana 事务管理器,则使用完整的 JTA 事务。如果 PlatformTransactionManager 定义为本地 Blueprint < bean&gt;,例如 org.springframework.jms.connection.JmsTransactionManager,则使用本地事务。

事务处理指的是启动、提交和回滚事务的步骤。本节介绍通过编程和配置控制事务处理的机制。

9.1. 通过标记路由进行事务处理

Apache Camel 提供了在路由中启动事务的简单机制。在 Java DSL 中插入 transacted () 命令,或者在 XML DSL 中插入 <transacted /> 标签。

图 9.1. 通过标记路由来划分

txn demarcation 01

翻译处理器取消处理,如下所示:

  1. 当交换进入转换处理器时,转换的处理器调用默认事务管理器来开始事务,并将事务附加到当前线程。
  2. 当交换到达剩余的路由结束时,转换的处理器调用事务管理器来提交当前的事务。

9.1.1. 使用 JDBC 资源的路由示例

图 9.1 “通过标记路由来划分” 显示通过向路由中添加 transacted () DSL 命令进行事务的路由示例。遵循 transacted () 节点的所有路由节点都包含在事务范围内。在本例中,以下两个节点访问 JDBC 资源:

9.1.2. Java DSL 中的路由定义

以下 Java DSL 示例演示了如何通过使用 transacted () DSL 命令标记路由来定义事务路由:

import org.apache.camel.builder.RouteBuilder;

class MyRouteBuilder extends RouteBuilder {
    public void configure() {
        from("file:src/data?noop=true")
                .transacted()
                .bean("accountService","credit")
                .bean("accountService","debit");
    }
}

在本例中,file 端点读取一些 XML 格式文件,这些文件描述了资金从一个帐户传输到另一个帐户的传输。第一个 bean () 调用将指定资金总和计入 beneficiary 帐户,然后第二个 bean () 调用从发送者的帐户中减去指定资金总和。两个 bean () 调用都会导致对数据库资源的更新。假设数据库资源通过事务管理器绑定到事务,例如: 第 6 章 使用 JDBC 数据源

9.1.3. Blueprint XML 中的路由定义

前面的路由也可以在 Blueprint XML 中表示。& lt;transacted /> 标签将路由标记为事务,如以下 XML 所示:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...>

    <camelContext xmlns="http://camel.apache.org/schema/blueprint">
        <route>
            <from uri="file:src/data?noop=true" />
            <transacted />
            <bean ref="accountService" method="credit" />
            <bean ref="accountService" method="debit" />
        </route>
    </camelContext>

</blueprint>

9.1.4. 默认事务管理器和转换的策略

为分离事务,转换的处理器必须与特定的事务管理器实例关联。要保存您必须在每次调用 transacted () 时都指定事务管理器,转换的处理器会自动选择一个可靠的默认值。例如,如果您的配置中只有一个事务管理器实例,则转换的处理器隐式选择此事务管理器,并使用它来处理事务。

转换器的处理器也可以配置有 transacted 策略,该策略是 TransactedPolicy 类型,它封装了传播策略和事务管理器(详情请参阅 第 9.4 节 “事务传播策略” )。以下规则用于选择默认的事务管理器或事务策略:

  1. 如果只有一个 bean 是 org.apache.camel.spi.TransactedPolicy 类型,则使用此 bean。

    注意

    TransactedPolicy 类型是 SpringTransactionPolicy 类型的基本类型,如 第 9.4 节 “事务传播策略” 中所述。因此,这里引用的 bean 可以是 SpringTransactionPolicy bean。

  2. 如果存在类型为 org.apache.camel.spi.TransactedPolicy 的 bean,其 ID 为 ,PROPAGATION_REQUIRED,则使用此 bean。
  3. 如果只有一个 bean of org.springframework.transaction.PlatformTransactionManager 类型,则使用此 bean。

您还可以通过向 transacted () 提供 bean ID 作为参数来显式指定 bean。请参阅 第 9.4.4 节 “Java DSL 中带有 PROPAGATION_NEVER 策略的示例路由”

9.1.5. 事务范围

如果您将转换的处理器插入到路由中,则事务管理器每次通过此节点时都会创建一个新的事务。事务的范围定义如下:

  • 事务仅与当前线程关联。
  • 事务范围包括所有遵循转换处理器的路由节点。

任何在 transacted 处理器之前的路由节点都不在事务中。但是,如果路由以事务端点开头,则路由中的所有节点都位于事务中。请参阅 第 9.2.5 节 “路由开始时的事务端点”

考虑以下路由:它不正确,因为 transacted () DSL 命令错误地出现在访问数据库资源的 first bean () 调用后:

// Java
import org.apache.camel.builder.RouteBuilder;

public class MyRouteBuilder extends RouteBuilder {
    ...
    public void configure() {
        from("file:src/data?noop=true")
                .bean("accountService", "credit")
                .transacted()  // <-- WARNING: Transaction started in the wrong place!
                .bean("accountService", "debit");
    }
}

9.1.6. 事务路由中没有线程池

务必要了解,给定的事务只与当前线程关联。您不能在事务路由中间创建线程池,因为新线程中的处理不会参与当前的事务。例如,以下路由被绑定到导致问题:

// Java
import org.apache.camel.builder.RouteBuilder;

public class MyRouteBuilder extends RouteBuilder {
    ...
    public void configure() {
        from("file:src/data?noop=true")
                .transacted()
                .threads(3)  // WARNING: Subthreads are not in transaction scope!
                .bean("accountService", "credit")
                .bean("accountService", "debit");
    }
}

由于 threads () DSL 命令与 transacted 路由不兼容,如前面的路由是一定的破坏。即使 threads () 调用在 transacted () 调用前面,路由也不会按预期工作。

9.1.7. 将路由拆分为片段

如果您想要将路由拆分为片段,并且每个路由片段都参与当前事务,您可以使用 direct: 端点。例如,要将交换发送到单独的路由片段,具体取决于传输量大(不等于 100)还是小(不等于 100),您可以使用 choice () DSL 命令和直接端点,如下所示:

// Java
import org.apache.camel.builder.RouteBuilder;

public class MyRouteBuilder extends RouteBuilder {
    ...
    public void configure() {
        from("file:src/data?noop=true")
                .transacted()
                .bean("accountService", "credit")
                .choice().when(xpath("/transaction/transfer[amount > 100]"))
                .to("direct:txbig")
                .otherwise()
                .to("direct:txsmall");

        from("direct:txbig")
                .bean("accountService", "debit")
                .bean("accountService", "dumpTable")
                .to("file:target/messages/big");

        from("direct:txsmall")
                .bean("accountService", "debit")
                .bean("accountService", "dumpTable")
                .to("file:target/messages/small");
    }
}

direct:txbig 和以 direct:txsmall 开头的片段都参与当前的事务,因为直接端点是同步的。这意味着,片段在与第一个路由片段相同的线程中执行,因此它们包含在相同的事务范围内。

注意

您不能使用 seda 端点来加入路由片段。seda 消费者端点创建一个新的线程(或线程),以执行路由片段(异步处理)。因此,片段不会参与原始的事务。

9.1.8. 资源端点

当 Apache Camel 组件显示为路由的目标时,以下 Apache Camel 组件充当资源端点,例如,如果它们出现在 to () DSL 命令中。也就是说,这些端点可以访问事务资源,如数据库或持久队列。资源端点可以参与当前的事务,只要它们与启动当前事务的转换处理器相同的事务管理器关联。

  • ActiveMQ
  • AMQP
  • 休眠
  • iBatis
  • JavaSpace
  • JBI
  • JCR
  • JDBC
  • JMS
  • JPA
  • LDAP

9.1.9. 使用资源端点的示例路由

以下示例显示了具有资源端点的路由。这将向两个不同的 JMS 队列发送资金传输订单。信用 队列处理了接收方帐户的顺序。解封 队列处理以取消发送者帐户的顺序。只有存在对应的 debit 时才应有学分。因此,您要将 enqueueing 操作放在单个事务中。如果事务成功,则信用订购和下序都将排队。如果发生错误,则既不会排队任何顺序。

from("file:src/data?noop=true")
        .transacted()
        .to("jmstx:queue:credits")
        .to("jmstx:queue:debits");
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.