一、使用java原生事务
RabbitMQ的事务机制与事务有关的主要有三个方法:
- txSelect()
- txCommit()
- txRollback()
txSelect主要用于将当前channel设置成transaction模式,txCommit用于提交事务,txRollback用于回滚事务。
当我们使用txSelect提交开始事务之后,我们就可以发布消息给Broke代理服务器,如果txCommit提交成功了,则消息一定到达了Broke了,如果在txCommit执行之前Broker出现异常崩溃或者由于其他原因抛出异常,这个时候我们便可以捕获异常通过txRollback方法进行回滚事务了。这套事务主要代码为:
channel.txSelect();
channel.basicPublish(exchange, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes());
channel.txCommit();
即消息的分发过程为:
- Client发送Tx.Select
- Broker发送Tx.Select-Ok(在它之后,发送消息)
- Client发送Tx.Commit
- Broker发送Tx.Commit-Ok
二、结合SpringBoot使用事务
在SpringBoot中主要是通过封装的RabbitTemplate模板来实现消息的发送,这里主要也是分为两种情况,使用RabbitTemplate同步发送,或者异步发送。
注意:发布确认和事务。(两者不可同时使用)在channel为事务时,不可引入确认模式;同样channel为确认模式下,不可使用事务。
所以在使用事务时,在application.properties中,需要将确认模式更改为false。
# 支持发布确认
spring.rabbitmq.publisher-confirms=false
A、同步
通过设置RabbitTemplate的channelTransacted为true,来设置事务环境,使得可以使用RabbitMQ事务。如下:
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RabbitTemplate rabbitTemplateNew() {
RabbitTemplate template = new RabbitTemplate(connectionFactory());
template.setChannelTransacted(true);
return template;
}
这里与前面我们讲解的原生事务是一致的,而当发送消息出现异常时,就会响应执行事务回滚。
B、异步
刚才我们讲解的是同步的情况,现在我们讲解一下异步的形式。在异步当中,主要使用MessageListener 接口,它是 Spring AMQP 异步消息投递的监听器接口。而MessageListener的实现类SimpleMessageListenerContainer则是作为了整个异步消息投递的核心类存在。
接下来我们开始介绍使用异步的方法,同样表示需要的外部事务,用户需要在容器配置的时候指定PlatformTransactionManager的实现。代码如下:
@Bean
public SimpleMessageListenerContainer messageListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory());
container.setTransactionManager(rabbitTransactionManager());
container.setChannelTransacted(true);
// 开启手动确认
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
container.setQueues(transitionQueue());
container.setMessageListener(new TransitionConsumer());
return container;
}
这段代码我们是添加在config下的RabbitConfig.java下,通过配置事务管理器,将channelTransacted属性被设置为true。
在容器中配置事务时,如果提供了transactionManager,channelTransaction必须为true,使得如果监听器处理失败,并且抛出异常,那么事务将进行回滚,那么消息将返回给消息代理;如果为false,外部的事务仍然可以提供给监听容器,造成的影响是在回滚的业务操作中也会提交消息传输的操作。
通过使用RabbitTransactionManager,这个事务管理器是PlatformTransactionManager接口的实现,它只能在一个Rabbit ConnectionFactory中使用。
注意:这种策略不能够提供XA事务,例如在消息和数据库之间共享事务。
还需要RabbitTransactionManager和TransitionConsumer,代码如下:
/**
* 声明transition2队列
*
* @return
*/
@Bean
public Queue transitionQueue() {
return new Queue("transition2");
}
/**
* 事务管理
*
* @return
*/
@Bean
public RabbitTransactionManager rabbitTransactionManager() {
return new RabbitTransactionManager(connectionFactory());
}
/**
* 自定义消费者
*/
public class TransitionConsumer implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
byte[] body = message.getBody();
System.out.println("TransitionConsumer: " + new String(body));
// 确认消息成功消费
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
// 除以0,模拟异常,进行事务回滚
// int t = 1 / 0;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。