消费者实现应用内分布式事务

来源:互联网 发布:天刀神威女捏脸数据 编辑:程序博客网 时间:2024/05/18 09:07
在《生产者实现应用内分布式事务管理》中我们已经实现了消息生产与关系型数据库MySQL的应用内分布式事务,结合上一章《消费者JmsListener应用源码浅析》中对源码的分析,本章将实现消费者实现应用内分布式事务。

本章概要

1、基础工程目录;
2、新增事务相关代码案例;
3、事务验证;

实践

1、首先看下本工程的目录

红色部分为在《优化生产者连接工厂(带有session缓存)》章节中已经实现部分,本章节不在重复说明,本次主要实现
JmsListenerContainerConfiguration、Consumer

2、在《消费者JmsListener应用源码浅析》章节中已经说明,需要XA连接工厂实现JTA事务管理,故我们务必注意:
/** * 注入MQ连接工厂 */@Autowired//@Qualifier(value="jmsConnectionFactory")@Qualifier(value="xaJmsConnectionFactory")private ConnectionFactory connectionFactory;/** * 创建带有缓冲session的连接工厂 * @return */@Bean(name="cachingConnectionFactory")@Primarypublic CachingConnectionFactory getConnectionFactory(){CachingConnectionFactory cachingConnectionFactory=new CachingConnectionFactory(); //目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactorycachingConnectionFactory.setTargetConnectionFactory(connectionFactory);//Session缓存数量,这里属性也可以直接在这里配置cachingConnectionFactory.setSessionCacheSize(10);return cachingConnectionFactory;}
3、在JTATransactionConfig.java中已经实现了JtaTransactionManager注册:
@Configuration@EnableTransactionManagementpublic class JTATransactionConfig {......    @Bean(name = "transactionManagerJTA")    @DependsOn({ "userTransaction", "atomikosTransactionManager"})    public PlatformTransactionManager transactionManager() throws Throwable {        UserTransaction userTransaction = userTransaction();        AtomikosJtaPlatform.transaction = userTransaction;        TransactionManager atomikosTransactionManager = atomikosTransactionManager();        return new JtaTransactionManager(userTransaction, atomikosTransactionManager);    }}
4、本次的消息消费依旧采用@JmsListener注解异步消费,故我们的实现将基于自定义DefaultJmsListenerContainerFactory的bean实例:
@Configurationpublic class JmsListenerContainerConfiguration {@Autowiredprivate CachingConnectionFactory cachingConnectionFactory;private final ObjectProvider<DestinationResolver> destinationResolver;private final JtaTransactionManager transactionManager;private final ObjectProvider<MessageConverter> messageConverter;private final JmsProperties jmsProperties;JmsListenerContainerConfiguration(ObjectProvider<DestinationResolver> destinationResolver,JtaTransactionManager transactionManager, ObjectProvider<MessageConverter> messageConverter,JmsProperties jmsProperties) {this.destinationResolver = destinationResolver;this.transactionManager = transactionManager;this.messageConverter = messageConverter;this.jmsProperties = jmsProperties;}@Bean(name = { "jmsListenerContainerFactory" })public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();factory.setConnectionFactory(cachingConnectionFactory);factory.setPubSubDomain(jmsProperties.isPubSubDomain());if (this.transactionManager != null) {factory.setTransactionManager(transactionManager);} else {factory.setSessionTransacted(Boolean.valueOf(true));}JmsProperties.Listener listener = jmsProperties.getListener();factory.setAutoStartup(listener.isAutoStartup());if (listener.getAcknowledgeMode() != null) {factory.setSessionAcknowledgeMode(Integer.valueOf(listener.getAcknowledgeMode().getMode()));}String concurrency = listener.formatConcurrency();if (concurrency != null)factory.setConcurrency(concurrency);return factory;}}
5、实现一个消费者:
@Componentpublic class Consumer {@Autowired@Qualifier(value="jmsQueueMessagingTemplate")private JmsMessagingTemplate jmsQueueMessagingTemplate;@Autowired@Qualifier("queue")private Queue queue;@Autowiredprivate UserRepository userRepository;@JmsListener(destination = "my.consuqueue",containerFactory="jmsListenerContainerFactory")//ActiveMQ.DLQpublic void receiveQueue(String text) throws Exception {System.out.println("消费者:来源于生产者2的消息:"+text);this.jmsQueueMessagingTemplate.convertAndSend(this.queue, "生产者辛苦生产的点对点消息成果");System.out.println("生产者:辛苦生产的点对点消息成果");List<User> list=new ArrayList<User>(10);list.add(new User("111","111"));list.add(new User("12211","222"));list.add(new User("333","333"));for(User user:list){userRepository.save(user);}throw new Exception("出现异常啦");}}
预期:存在异常的情况下,my.consuqueue队列中消息不会被消费,my.queue队列在broker中不会生产新的消息,并且数据库中不会新增用户数据;无异常情况则my.consuqueue队列被全部消费,并且生产同等数量的my.queue队列消息,MySQL数据库中新增3被数量的用户;
5.1、首先查看目前的消息数据情况:

用户:

持久化的queue消息

5.2、验证存在异常执行后的结果:

用户

持久化的queue消息

5.3、无异常情况下 ,考虑到目前my.consuqueue仅有一个数据,为了更好的验证效果,我们本次监听ActiveMQ.DLQ队列:

持久化的消息,新增3个queue消息

用户,新增9个用户数据


总结,消费者应用内分布式事务验证成功。同时简单的跑了一下《生产者实现应用内分布式事务管理》的单元测试,@Transactional注解事务同步也生效。貌似这个没有改动也不会不生效。






1 0
原创粉丝点击