事务消息与数据库的事务类似,只是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.执行程序: