Rabbitmq之发送端事务和确认

官网说明

为什么存在确认机制

根据官网翻译过来:

根据定义,使用消息传递代理(如rabbitmq)的系统是分布式的。由于发送的协议方法(消息)不能保证到达对等方或被对等方成功地处理,因此发布者和消费者都需要一种传递和处理确认的机制。rabbitmq支持的几个消息传递协议提供了这样的特性。

它们对于从发布服务器到rabbitmq节点以及从rabbitmq节点到消费者的可靠交付都是必不可少的。换言之,它们对于数据安全至关重要,应用程序和rabbitmq节点一样负责数据安全。


发送端确认和失败回调

要确保生产者生产的消息成功到达队列,有两个步骤,生产者到交换机,交换机到队列

发送端确认是要确保生产者生产的消息成功到达交换机

失败回掉是消息从交换机成功路由到队列


保证消息成功到达交换机有两种方式

1.通过AMOP提供的事务机制

保证消息不会丢失的唯一方法是使用事务——使通道具有事务性,然后对每个消息或消息集发布、提交。在这种情况下,事务是不必要的重量级,并将吞吐量减少250倍。为了补救这一点,引入了确认机制。它模拟了协议中已经存在的使用者确认机制。

配置类需要开启声明式事务,RabbitTemplate设置开启事务,AMOP事务不能和确认机制同时存在

RabbitTemplate的使用案例(同步),由调用者提供外部事务,在模板中配置了channe-transacted=true。通常是首选,因为它是非侵入性的(低耦合)

@Configuration
@EnableTransactionManagement
public class RabbitmqConfig {

	@Bean
	public RabbitTransactionManager rabbitTransactionManager(ConnectionFactory connectionFactory){
		RabbitTransactionManager rabbitTransactionManager = new RabbitTransactionManager(connectionFactory);
		return rabbitTransactionManager;
	}

	@Bean
	public ConnectionFactory connectionFactory(){
		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
		//ip
		connectionFactory.setHost("127.0.0.1");
		connectionFactory.setPort(5672);
		connectionFactory.setUsername("helloWorld");
		connectionFactory.setPassword("helloWorld");
		connectionFactory.setVirtualHost("testHost");

		return connectionFactory;
	}

	@Bean
	public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
		RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
		//开启事务
		rabbitTemplate.setChannelTransacted(true);

		
		return rabbitTemplate;
	}

	@Bean
	public DirectExchange  defaultExchange() {
		return new DirectExchange("directExchange");
	}

	@Bean
	public Queue queue() {
		//名字  是否持久化

		return new Queue("testQueue", false);
	}

	@Bean
	public Binding binding() {
		//绑定一个队列  to: 绑定到哪个交换机上面 with:绑定的路由建(routingKey)
		return BindingBuilder.bind(queue()).to(defaultExchange()).with("direct.key");
	}

}
@Component
public class MessageSender {

	@Autowired
	RabbitTemplate rabbitTemplate;

	@Transactional
	public void send(){

		CorrelationData correlationData = new CorrelationData("订单ID");
		rabbitTemplate.convertAndSend("directExchange","direct.key","hello",correlationData);
		System.out.println(1/0);
	}
}

 事务开启的时候,同一个事务中有异常消息不会发送到消息队列

去掉@Transactionl或者不设置rabbitTemplate中的事务,消息会发送到队列

 

但是事务的方式官网上不推荐,太影响性能了 

2.开启确认模式

若要启用“确认”,客户端将发送confirm.select方法。根据是否设置了等待,代理可以用确认。一旦在通道使用confirm.select方法,就称其为confirm模式。事务通道不能置于确认模式,并且一旦通道处于确认模式,就不能使其成为事务通道。

@Configuration
public class RabbitmqConfig {


	@Bean
	public ConnectionFactory connectionFactory(){
		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
		//ip
		connectionFactory.setHost("127.0.0.1");
		connectionFactory.setPort(5672);
		connectionFactory.setUsername("helloWorld");
		connectionFactory.setPassword("helloWorld");
		connectionFactory.setVirtualHost("testHost");

		//发送方确认
		connectionFactory.setPublisherConfirms(true);

		connectionFactory.setPublisherReturns(true);
		return connectionFactory;
	}

	@Bean
	public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
		RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
		rabbitTemplate.setMandatory(true);

		//确认回调
		rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
			@Override
			public void confirm(CorrelationData correlationData, boolean b, String s) {
				System.out.println(b);
				System.out.println(s);
				System.out.println(correlationData);
			}
		});

        
        //失败回调
		rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
			@Override
			public void returnedMessage(Message message, int i, String s, String s1, String s2) {
                System.out.println(message);
				System.out.println(s);
				System.out.println(s1);
				System.out.println(s2);
			}
			}
		});



		return rabbitTemplate;
	}

	@Bean
	public DirectExchange  defaultExchange() {
		return new DirectExchange("directExchange");
	}

	@Bean
	public Queue queue() {
		//名字  是否持久化

		return new Queue("testQueue", false);
	}

	@Bean
	public Binding binding() {
		//绑定一个队列  to: 绑定到哪个交换机上面 with:绑定的路由建(routingKey)
		return BindingBuilder.bind(queue()).to(defaultExchange()).with("direct.key");
	}

}
@Component
public class MessageSender {

	@Autowired
	RabbitTemplate rabbitTemplate;

	public void send(){

		CorrelationData correlationData = new CorrelationData("订单ID");
		rabbitTemplate.convertAndSend("directExchange","direct.key","hello",correlationData);
	}
}

生产者发送消息后如果消息到达exchange,就会回调confirm方法,ack为true

如果消息没有到达exchange,就会回调confirm方法,ack为false

exchange路由到queue成功就不会回调return方法

exchange路由到queue不成功就会回调return方法

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章