6

我正在开发一个同时使用 JMS 和 Hibernate 的独立应用程序。

如果我想跨两种资源进行交易,文档建议必须使用 JTA。

但是,现在使用 @Transaction 注释的 DAO 方法(和 HibernateTransactionManager),这似乎已经奏效了。当我在 JmsTemplate 上调用 send() 时,不会立即发送消息,而是在方法返回时将 JMS 会话与 Hibernate 会话一起提交。

我不知道没有 JtaTransactionManager 怎么可能,所以我检查了源代码。事实证明,Hibernate 的包装器和 JmsTemplate 都使用 TransactionSynchronizationManager 注册会话,并且 JMS 会话将在 Hibernate 会话提交时提交。

这和 JTA 交易有什么不同。我可以用它来代替后者吗?

4

2 回答 2

15

简而言之,没有 JTATransactionManager 和 XA 感知数据源,您将无法获得对两阶段提交的支持。

您所看到的是两个仅支持一阶段提交的本地事务的协调。大致执行这一系列事件......

  1. 启动 JMS 事务
  2. 读取 JMS 消息
  3. 启动 JDBC 事务
  4. 写入数据库
  5. 提交 JDBC 事务
  6. 提交/确认 JMS

JMS 事务将首先包装嵌套的 JDBC 事务,这样如果 Hibernate/JDBC 提交失败,JMS 队列将回滚。您的 JMS 侦听器容器不应设置 acknowledge="auto",而是在发送确认之前等待 Hibernate 事务完成。

如果您只有这两个资源,那么您必须考虑的问题是当 Hibernate 成功持久化时,您会在确认 JMS 服务器之前获得一个异常。不是什么大问题,因为 JMS 消息没有丢失,您将再次阅读它。

然而

  1. 您必须编写 MessageListener 来处理来自服务器的重复消息

  2. 您还必须处理由于数据错误而无法处理的消息,并最终陷入无限循环尝试使用它。在这种情况下,服务器可能被配置为将消息移动到“死消息队列”,或者您自己在 MessageListener 中处理这个

其他选项和进一步阅读

如果您的 JMS 服务器不支持 XA(全局)事务,这几乎是您唯一的解决方案。

如果 JMS 服务器确实支持 XA 事务但 JDBC 不支持,那么您可以使用 JTATransactionManager 并使用LastResourceCommitOptimisation。有一些开源的 JTATransactionManager 可以像 JOTM 一样使用

这篇 JavaWorld 文章更详细地介绍了您的问题空间。

于 2012-05-29T13:44:52.140 回答
1

尽管布拉德已经详细回答了这个问题,但我想解决您查询的一个非常具体的部分:-

如果没有 JtaTransactionManager,我不知道这怎么可能

来自 spring 文档:- 当检测到 JTA 环境时,Spring 的 JtaTransactionManager 将用于管理事务

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-jta.html

于 2017-09-25T10:38:46.527 回答