事务消息与数据库的事务类似,只是MQ的消息是要保证消息是否会全部发送成功,防止消息丢失的一种策略。
  RabbitMQ有两种策略来解决这个问题:
  1.通过AMQP的事务机制实现
  2.使用生产者确认模式实现

  本文讲事务性机制。

1. 生产者

using RabbitMQMsgProducer.MessageProducer;
using Microsoft.Extensions.Configuration;
using System;
using System.IO;
using RabbitMQMsgProducer.ExchangeDemo;
using RabbitMQMsgProducer.MessageConfirm;

namespace RabbitMQMsgProducer
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                {
                    // 事务性消息
                    ProducerMsgTx.Send();
                }
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

 

using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Text;

namespace RabbitMQMsgProducer.MessageConfirm
{
    public class ProducerMsgTx
    {
        public static void Send()
        {
            ConnectionFactory factory = new ConnectionFactory();
            factory.HostName = "localhost";//服务地址
            factory.UserName = "guest";//用户名
            factory.Password = "guest";//密码 
            string queueName01 = "MsgTxQueue01";
            string queueName02 = "MsgTxQueue02";
            string exchangeName = "MsgTxExchange";
            string routingKey01 = "MsgTxKey01";
            string routingKey02 = "MsgTxKey02";
            using (var connection = factory.CreateConnection())
            {
                //创建通道channel
                using (var channel = connection.CreateModel())
                {
                    Console.WriteLine("the producer is ready . GO !");
                    // 声明队列
                    channel.QueueDeclare(queue: queueName01, durable: true, exclusive: false, autoDelete: false, arguments: null);
                    channel.QueueDeclare(queue: queueName02, durable: true, exclusive: false, autoDelete: false, arguments: null);
                    //声明交换机exchang
                    channel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
                    //绑定exchange和queue
                    channel.QueueBind(queue: queueName01, exchange: exchangeName, routingKey: routingKey01);
                    channel.QueueBind(queue: queueName02, exchange: exchangeName, routingKey: routingKey02);
                    string message = "";
                    //发送消息
                    //在控制台输入消息,按enter键发送消息
                    while (true)
                    {
                        message = Console.ReadLine();
                        bool isOk = message.Equals("quit", StringComparison.CurrentCultureIgnoreCase);
                        if (isOk) { break; }
                        var body = Encoding.UTF8.GetBytes(message);
                        try
                        {
                            //开启事务机制
                            channel.TxSelect(); //事务是协议支持的
                            //发送消息
                            //同时给多个队列发送消息;要么都成功;要么都失败;
                            channel.BasicPublish(exchange: exchangeName, routingKey: routingKey01, basicProperties: null, body: body);
                            channel.BasicPublish(exchange: exchangeName, routingKey: routingKey02, basicProperties: null, body: body);

                            //throw new Exception();

                            //事务提交
                            channel.TxCommit(); //只有事务提交成功以后,才会真正的写入到队列里面去
                            Console.WriteLine($"the msg : _ {message} _ is send to broker . success .");
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"the msg : _ {message} _ is send to broker . fail .");
                            channel.TxRollback(); //事务回滚
                            //可能在这里还重试一下。。。
                            throw;
                        }
                    }
                    Console.Read();
                }
            }
        }
    }
}

2. 执行代码,产生交换机路由和队列

 

 

 

 2.1 执行命令窗口,等待输入:

 

发送 hello ,失败,队列中无值。

 

 3. 修改异常处理模拟发送消息失败:

修改程序

 

 4.执行程序:

 

 

 

 

posted on 2021-01-18 19:47  Fletcher  阅读(101)  评论(0编辑  收藏  举报