使用@JmsListener监听IBM MQ时数据库回滚失效求助
问题分析
当前配置仅使用JmsTransactionManager管控IBM MQ的事务,数据库的@Transactional是独立的本地事务,两者不在同一事务上下文。当步骤4抛出异常时,MQ事务触发回滚,但数据库事务已提前提交,导致数据未回滚。
解决方案
需要将JMS事务与数据库事务绑定到同一全局事务中,确保两者要么同时提交,要么同时回滚。以下是具体实现步骤:
1. 配置事务管理器整合
使用ChainedTransactionManager将数据库事务管理器与JMS事务管理器链式整合,实现事务联动。
@Configuration public class JmsConfig { // 数据库事务管理器 @Bean public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } // JMS事务管理器 @Bean public JmsTransactionManager jmsTransactionManager(MQConnectionFactory connectionFactory) { return new JmsTransactionManager(connectionFactory); } // 整合数据库与JMS事务管理器 @Bean public ChainedTransactionManager chainedTransactionManager(DataSourceTransactionManager dtm, JmsTransactionManager jtm) { // 顺序:先JMS后数据库,回滚时会逆序执行,确保两者都能回滚 return new ChainedTransactionManager(jtm, dtm); } // 配置JMS监听容器工厂,绑定整合后的事务管理器 @Bean public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(MQConnectionFactory connectionFactory, ChainedTransactionManager ctm) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); factory.setTransactionManager(ctm); factory.setSessionTransacted(true); factory.setConcurrency("1-3"); // 根据业务调整并发数 return factory; } // JmsTemplate绑定整合后的事务管理器 @Bean public JmsTemplate jmsTemplate(MQConnectionFactory connectionFactory, ChainedTransactionManager ctm) { JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory); jmsTemplate.setTransactionManager(ctm); jmsTemplate.setSessionTransacted(true); return jmsTemplate; } }
2. 调整监听器代码
移除类上的@Transactional(监听容器已通过事务管理器管控全局事务),确保异常能正常抛出触发回滚:
@Service @JmsListener(containerFactory="jmsListenerContainerFactory", destination="ibm.mq.request") public class TestListener { @Autowired private JmsTemplate jmsTemplate; @Autowired private OrderMapper orderMapper; // 数据库操作Mapper/Repository public void receiveMessage(String message) { // 1. 消息转对象并执行业务逻辑 Order order = parseMessage(message); // 2. 插入数据库 orderMapper.insert(order); // 3. 生成响应消息并发送 String response = buildResponse(order); jmsTemplate.convertAndSend("ibm.mq.response", response); } // 省略消息解析与响应构建方法 private Order parseMessage(String message) { ... } private String buildResponse(Order order) { ... } }
关键说明
ChainedTransactionManager会按顺序提交事务,回滚时逆序执行,确保JMS和数据库事务联动。若需更严谨的分布式事务(两阶段提交),可替换为JtaTransactionManager,但需配置XA版的MQ连接工厂与数据库数据源。- 监听方法不能捕获异常后自行处理,必须让异常抛出,事务管理器才会触发全局回滚。
- 确保IBM MQ连接工厂已开启事务支持,避免事务失效。
内容的提问来源于stack exchange,提问作者Bifrost
相关产品推荐
相关产品推荐

