我正在与JTA、两阶段提交、JMS和jdbc事务作斗争。这个想法是(简而言之)
- 接收队列上的消息
- 执行一些数据库操作
- 确认消息,当db操作成功时
所以我得到了XAQueueConnectionFactory
,创建了XAQueueSession
,从会话中创建了一个接收器,并设置了一个消息侦听器。
在侦听器内部,在onMessage
方法中,我开始我的用户事务,执行jdbc内容并提交事务,或者在出现问题时执行回滚。现在我期望(也就是"希望")当用户事务提交时,消息将被确认。
但这不会发生,消息仍然在队列中,并一次又一次地重新传递。
我错过了什么?我检查了会话,确认模式确实是"SESSION_TRANSACTED
",getTransacted
返回true。
我没有Java EE容器,没有spring,没有消息驱动的bean。我使用独立的JTA bitronix
您实际上并不需要XA。只需遵循您的算法:接收消息,执行DB操作,然后确认消息…这就是解决方案。(对于事务会话,您可能只选择显式CLIENT_ACKNOWLEDGE。)如果您的应用程序在执行DB操作时失败,不要ack JMS消息,它将被重新交付。如果你的应用程序在DB txn之后和ack之前失败,那么消息将被重新传递——但是你可以检测到这一点(消息上的redelivered标志将被设置为true),并且你可以根据数据库的状态决定是否重新处理消息。
当您在侦听器中说开始用户事务时,这似乎暗示您正在使用Bean管理事务(BMT)。这样做有什么好的理由吗?
如果你使用容器管理事务(CMT),你想要的将是免费的。
据我所知,这在BMT中是不可能的,因为UserTransaction将不参与,也不能参与为消息创建的事务。但是您可能需要再次检查Java EE规范。
编辑:对不起,我意识到你没有使用Java EE容器已经太晚了。
您确定在侦听器内启动的用户事务是为消息启动的事务的一部分吗?您似乎为db工作启动了一个独立的事务。
如果您不使用容器,谁提供JMS实现,即XAQueueConnectionFactory等?
我认为XA不应该使用事务会话。