RabbitMQ高级特性 - 事务消息

文章目录

RabbitMQ 事务消息


概述

RabbitMQ 的 AMQP 协议实现了事务机制,允许开发者保证消息的发送和接收时原子性的,也就是说,要么消息全都发送成功,要么全都发送失败(只与发送方有关).

实现原理

AMQP 事务实现类似于传统数据库事务,允许在一个事务中发送多条消息,并在最后提交或回滚.

  • 事务开始:客户端发送 tx.select 方法,RabbitMQ 开启一个新的事务上下文.
  • 事务内的操作:客户端发送消息 basic.publish,RabbitMQ 将这些消息暂存在内存中,并标记为未提交.
  • 事务提交:客户端发送 tx.commit 方法,RabbitMQ 将所有暂存的消息写入队列,并且如果消息标记为持久化,那么就把消息保存到磁盘.
  • 事务回滚:客户端发送 tx.rollback 方法,RabbitMQ 丢弃所有暂存的消息,不会写入队列.

代码实现

不采用事务

a)配置文件

yml 复制代码
spring:
  application:
    name: rabbitmq
  rabbitmq:
    host: env-base
    port: 5672
    username: root
    password: 1111

b)配置常量

kotlin 复制代码
object MQConst {

    // 事务
    const val TRANS_QUEUE = "trans.queue"

}

c)定义队列

kotlin 复制代码
@Configuration
class MQConfig {

    @Bean
    fun transQueue() = Queue(MQConst.TRANS_QUEUE)

}

d)发送接口

两条消息之间故意触发异常.

kotlin 复制代码
@RestController
@RequestMapping("/mq")
class MQApi(
    val rabbitTemplate: RabbitTemplate,
) {

    @RequestMapping("/trans-close")
    fun transClose(): String {
        rabbitTemplate.convertAndSend("", MQConst.TRANS_QUEUE, "trans msg 1")
        //触发异常
        val a = 1 / 0
        rabbitTemplate.convertAndSend("", MQConst.TRANS_QUEUE, "trans msg 1")
        return "ok"
    }

}

e)效果如下:

此时队列中只有一条消息,说明消息不具备事务特性.

采用事务

a)配置两个 Bean

  1. 由于事务对整个 RabbitTemplate 都会有影响,因此这里重新定义一个 Template bean.
  2. 还需要配置一个 RabbitMQ事务管理器.
kotlin 复制代码
@Configuration
class GlobalConfig {

    @Bean("transRabbitTemplate")
    fun transRabbitTemplate(
        connectionFactory: ConnectionFactory
    ): RabbitTemplate {
        val mq = RabbitTemplate(connectionFactory)
        mq.isChannelTransacted = true // 开启事务机制
        return mq
    }

    @Bean
    fun rabbitTransactionManager(
        connectionFactory: ConnectionFactory
    ): RabbitTransactionManager {
        return RabbitTransactionManager(connectionFactory)
    }

}

b)如下步骤:

  • 使用新定义的事务 mq bean.
  • 在方法上加上 @Transaction 注解.
kotlin 复制代码
@RestController
@RequestMapping("/mq")
class MQApi(
    val transRabbitTemplate: RabbitTemplate,
) {

    @Transactional
    @RequestMapping("/trans-open")
    fun transOpen(): String {
        transRabbitTemplate.convertAndSend("", MQConst.TRANS_QUEUE, "trans msg 1")
        //触发异常
        val a = 1 / 0
        transRabbitTemplate.convertAndSend("", MQConst.TRANS_QUEUE, "trans msg 1")
        return "ok"
    }

}

c)效果演示

相关推荐
茶杯梦轩2 天前
从零起步学习RabbitMQ || 第三章:RabbitMQ的生产者、Broker、消费者如何保证消息不丢失(可靠性)详解
分布式·后端·面试
回家路上绕了弯3 天前
深入解析Agent Subagent架构:原理、协同逻辑与实战落地指南
分布式·后端
用户8307196840824 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
用户8307196840825 天前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者7 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者9 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧10 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖10 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农10 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者10 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端