Spring 事务路由和事务端点、事务提交顺序

Spring 事务路由和事务端点、事务提交顺序,spring,transactions,apache-camel,camel-jms,Spring,Transactions,Apache Camel,Camel Jms,我的路线如下所示 fromjms:queue:IN\u queue//事务端点 .transactedrequired//B发送策略,需要传播和JPATxManager .beansomeBean,readFromDB//C readFromDB .beansomeBean,writeToDB//D写入数据库 .tofile:/home/src?fileName=demo${id}.txt 我知道,在一次轮询中,JMS消费者将在每次轮询时发出JMS事务,并附加到 线 此外,B中的事务节点将在交换

我的路线如下所示

fromjms:queue:IN\u queue//事务端点 .transactedrequired//B发送策略,需要传播和JPATxManager .beansomeBean,readFromDB//C readFromDB .beansomeBean,writeToDB//D写入数据库 .tofile:/home/src?fileName=demo${id}.txt

我知道,在一次轮询中,JMS消费者将在每次轮询时发出JMS事务,并附加到 线 此外,B中的事务节点将在交换到达JPA事务之后分叉JPA事务 并连接到线上

请在下面找到我的问题:

两个不同的事务是否可以像上面那样连接到一个线程? 如果是,哪一个应该被暂停? 上述路由的提交和回滚顺序应该是什么

注意:我并没有从《骆驼行动》第二版的书中找到任何明显的答案,所以请指导我


抱歉,我无法回答您的具体问题,但我可以提供一些有关您路线交易的具体信息

您有3个具有不同事务范围的不同系统

您从中消费的JMS代理 您从中读取和写入的数据库,并为其配置了JPA TxManager 文件系统完全没有事务作为目标 首先,如果希望跨JMS和数据库实现事务安全,就必须使用XA事务

然后,不清楚您是否希望JMS使用者进行事务处理,因为您的路由中存在事务处理,或者您是否确实使用本地JMS事务配置了JMS连接。我想你真的做了交易

让我们来谈谈在没有路线B线的情况下你得到了什么:

你从经纪人那里得到了交易 Camel通过您的路由处理消息 当路由处理过程中发生任何错误时,消息不会在代理上提交,因此会重新传递到路由 事务使用者打开的事务将通过Camel保持打开状态,直到路由成功处理

因此,唯一明显的问题是数据库写入后出现错误,这会触发重新交付,并再次完成数据库写入。写操作可能不是幂等的,因此不能发生两次

因此,要解决这些问题,您要么使用XA事务,要么只使用本地JMS事务,并为上述间隙实现补偿逻辑

另一方面,数据库事务没有任何好处,除非读写操作必须在事务中完成,但我怀疑两个单独的bean调用和一个JMS消费者的情况是否如此

下午好

这是你另一个问题的变体

委员会:

端点已事务化,这意味着您已将JMS组件标记为已事务化,JMS会话将由JMSTRANASCTIONManager管理

.transacted("required")   //(B) TX Policy with PROPAGATION_REQUIRED and 
JPATxManager
这不应该是JPA事务管理器,而是像Arjuna这样的JTA事务管理器。和您的另一个问题一样,您现在有一个JMS本地事务用于读取您的消息,还有一个本地JPA事务会话用于您的DB访问。您希望PlatformTransactionManager和JTA事务管理器为您同步本地事务

关于你的问题:

两个不同的事务是否可以像上面那样连接到一个线程

那真的没有任何意义

如果是,哪一个应该被暂停

没有什么会被暂停

上述路由的提交和回滚顺序应该是什么

DB读取不是事务性的,不需要提交。文件写入实际上会在JTA事务上下文关闭时发生。这将导致数据库写入。如果失败,那么DB读取就无关紧要了,消息将被放回源目标,文件写入将不会被调用

为各种事务管理器启用调试日志记录非常有用

我可以用痛苦的细节继续讨论这个问题。这是给burki的。我想你会非常感激的。非常微妙,而且经常发生

   from("jms:queue:SRC_QUEUE")
     .transacted("required")
     .to("jms1:queue:DEST_QUEUE") 
如果这两个端点被标记为Transact。。。但是您没有“交易”行吗?在消息侦听器上启动了一个JMS本地事务。这将在路由结束时提交。有两个独立的本地JMS事务。JTA事务管理器不会同步这些数据

实际发生的是调用消息“get”的提交。消息“put”没有实际提交。消息“put”在JMS会话关闭时提交。在JMS规范中,关闭连接本质上会提交任何事务。因此,由于这两个组件之间没有链接,“get”是 提交,然后关闭“put”会话

这意味着,如果在消息“get”的提交和消息“put”的会话关闭之间发生中断,您可能会丢失消息

这有意义吗?本地事务之间没有链接,所以Camel会按顺序关闭它们,在调用“put”之前先提交“get”

JTA事务同步是关键。您仍然有本地事务资源,而不是XA,但它们可以在相当轻量级的JTA事务上下文中得到很好的管理

   from("jms:queue:SRC_QUEUE")
     .transacted("required")
     .to("DB:transactedwrite")
     .to("jms1:queue:DEST_QUEUE") 

我不想费心去查找数据库插入的正确语法,但你知道了。在这种情况下,如果JMS“put”失败,您可以获得重复的DB插入。这不是“全部或全部”XA事务。事务按顺序提交。如果中间的一个成功,则下一个事务失败,那么“GET”将被回滚,并且您将得到副本到故障点。< /P>如果删除B中提到的事务,C和D会在事务中发生吗?我希望不是,因为JmsConsumer在一个无法提交JPA实体的环境中生成的事务。您的JMS消费者是否使用本地JMS事务?也就是说,不需要Spring Tx Manager,只需要配置为事务处理的JMS连接。我是否正确理解这一点,即当我使用Spring JTA Tx Manager而我不在应用服务器上时,Spring没有XA,但尽最大努力优化本地事务的处理,因此您描述的两个不同代理之间的潜在消息丢失是固定的?Spring PlatformTransactionManager只是一个需要实现的接口。例如,如果您不在应用程序服务器中,但正在使用Spring Boot,则可以包括Spring Boot starter jta narayana starter。这将连接Arjuna作为PlatformTransactionManager,您可以使用JTA同步事务。这意味着JTA实现能够在分布式事务中使用本地资源和非XA资源,并且在同步方面比使用两个本地事务的Camel做得更好。也就是说,在JMS示例中,您描述的丢失消息在JTA中是不可能的。
   from("jms:queue:SRC_QUEUE")
     .transacted("required")
     .to("DB:transactedwrite")
     .to("jms1:queue:DEST_QUEUE")