场景
最近在做某个极其变态的需求,近乎全量的更新整表。本着技术可以解决一切的态度,虽然很不情愿但是还是接下了这个烫手的山芋,于是乎,穷尽自己毕生所学,想到了一个借助mq异步多线程更新的还算凑合的办法。兴致勃勃的写完了,结果发现一个问题:由于最近刚刚切到spring-amqp框架,代码中使用rabbitTemplate发送消息后,如果遇到异常,消息还是会被发送到mq并且被消费者消费,此时我的业务逻辑还涉及到数据库的更新操作,如此一来岂不是一致性得不到保证,并且为了最大限度的分散更新压力,充分利用集群机器,我将每个表的更新分三条消息发送给mq,如果其中两条发送了到第三条没有发送成功,有两个消息被消费,一个没有被消费岂不是很尴尬。
问题
如何保证在spring事物中的数据库操作和mq发送消息的操作在一个事物中,即原子性,要么全部执行,要么全部回滚。
分析
由于对amqp发送的基础包操作很熟练,知道有一个事物机制发送消息,就是为了保证在异常出现时可以让mq服务器返回消息,而不至于被错误的消费。大体云云就是channel.txSelect()开启事物,然后basic发送消息,最后正常的话channel.txCommit提交事物,此时消息真正的发送到队列中去。如果有异常rollback即可。想到spring-amqp这么高级的框架肯定也会有这个操作的,果不其然让我发现了眉目,通过配置文件发线一个属性参数channelTransacted,通过一部分源码发现:
private <T> T doExecute(ChannelCallback<T> action, ConnectionFactory connectionFactory) {
Assert.notNull(action, "Callback object must not be null");
Channel channel = null;
boolean invokeScope = false;
// No need to check the thread local if we k