一、使用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();

即消息的分发过程为:

  1. Client发送Tx.Select
  2. Broker发送Tx.Select-Ok(在它之后,发送消息)
  3. Client发送Tx.Commit
  4. 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;
    }
}

柠檬时间
63 声望5 粉丝

遵循内心


引用和评论

0 条评论