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)效果演示

相关推荐
严肃小白兔4 小时前
Cloudflare Durable Objects 支持自动重试:分布式调用如何避免重复执行?
分布式
Pniubi4 小时前
基于RabbitMQ实现延迟队列
rabbitmq
方方洛5 小时前
ray教程-27-附录F-RayClient与runtime_env与多语言
人工智能·分布式·机器学习
方方洛1 天前
ray教程-25-附录E-端到端实战案例
人工智能·分布式·机器学习
一条泥憨鱼2 天前
【消息队列】ACK确认了什么:消息队列可靠投递的完整链路
java·后端·kafka·消息队列·rabbitmq
迅翼SwiftWing2 天前
编队系列(二)|固定翼如何依靠邻居信息保持队形?一致性控制、通信拓扑与分布式仿真实现,附仿真代码
分布式
ly76892 天前
幂等消费者与重试副作用:Kafka 端点接入时的去重边界
分布式·kafka·linq·apache camel·幂等消费者·重试副作用·去重边界
qq_452396232 天前
第三篇:《从 ZooKeeper 到 KRaft 的迁移实战:前置条件、三阶段流程与回滚策略》
分布式·zookeeper·云原生
真上帝的左手3 天前
30. 技术专题-‌应用框架组件-关系型数据库-MySQL-Mybatis
数据库·分布式·mysql·中间件·mybatis
程序猿乐锅3 天前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight