业务需求是,就是我本来是有一个order-queue队列绑定到了死信队列交换机order-dead-direct-exchange上,然后我的业务是,现在有一个用户下单但是没有付款,order-queue队列写入该条信息并计时24小时后如果用户还是未付款状态则移除到死信队列order-dead-queue中。问题来了,如果在这个24小时内,用户取消订单,这时候就要从order-queue队列中移除该条信息。怎么操作呢?
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private ConnectionFactory connectionFactory;
//取消订单
@PostMapping("/cancelOrder")
public Object cancelOrder(String productId,String dyOrderId,String cancelText,String buyerPaymentState,String orderDeliveryState,String state,String orderId,String buyerPaymentPrice) throws IOException, TimeoutException {
//删除rabbitMQ中order-queue队列中对应的值? 重新上架商品?
// 从 order-queue 队列中移除指定订单
Channel channel = connectionFactory.createConnection().createChannel(false);
boolean deleted = false;
while (!deleted) {
GetResponse response = channel.basicGet("order-queue", false);
if (response == null) {
break;
}
String messageValue = new String(response.getBody(), StandardCharsets.UTF_8);
if (messageValue.equals(productId+"_"+dyOrderId)) {
deleted = true;
channel.basicAck(response.getEnvelope().getDeliveryTag(), false);
continue;
}
channel.basicNack(response.getEnvelope().getDeliveryTag(), false, true);
}
channel.close();
这段代码使用 basicGet
方法接收队列中的消息,并使用 basicAck
方法手动确认消费。如果找到包含特定值的消息,就设置 deleted
为 true,并使用 basicAck
确认该消息的消费,然后跳过该消息,最终将其从队列中删除。如果消息的值不等于指定的值,则使用 basicNack
方法将消息放回队列中。这样我们就是实现了从队列中删除指定的值。
需要注意的是,当使用手动确认模式时,如果在消费消息后没有进行确认或拒绝,消息将一直处于 unack 状态,直到消费者关闭或重新连接。这可能会导致消息被重新投递,因此需要确保在处理完每个消息后进行确认或拒绝操作。
在RabbitMQ中,当消费者从队列中获取到一条消息并进行处理后,需要告诉服务器这条消息已经被成功处理了,这时可以使用basicAck
方法来确认消息的消费。而如果处理消息时发生了错误,需要将这条消息重新放回队列中,或者直接将消息丢弃,就可以使用basicNack
方法。
basicAck
方法表示消费者已经成功地处理了消息,并告诉RabbitMQ可以删除此消息。它的方法签名如下:
void basicAck(long deliveryTag, boolean multiple) throws IOException;
其中,deliveryTag
表示消息的唯一标识符,multiple
表示是否批量确认(如果设置为true,则表示确认所有小于等于deliveryTag
的消息)。
basicNack
方法则是表示消费者处理消息时发生了错误,需要将消息重新放回队列中,或者直接将消息丢弃。它的方法签名如下:
void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException;
其中,deliveryTag
和multiple
的含义与basicAck
方法相同,requeue
表示是否重新将消息放回队列(如果设置为true,则将消息重新放回队列,如果设置为false,则直接将消息丢弃)。
需要注意的是,basicNack
方法并不是所有的AMQP客户端都支持的。如果你的客户端不支持basicNack
方法,可以使用basicReject
方法来实现相同的效果。
basicReject
是AMQP协议提供的一个API,用于拒绝(reject)一条消息,并选择是否将消息重新投递到队列中。它与basicNack
类似,但有一些细微的区别。
basicReject的方法签名如下:
void basicReject(long deliveryTag, boolean requeue);
其中,deliveryTag
是消息投递标识符,requeue
表示是否将消息重新投递到队列中。
与basicNack
的区别在于,basicReject
只能拒绝单个消息,而basicNack
可以拒绝多个消息。此外,basicReject
无法设置拒绝原因,而basicNack
可以设置拒绝原因。
需要注意的是,使用basicReject
或basicNack
将会导致RabbitMQ重新将消息投递到队列中,这可能会导致消息的不断重试,因此需要谨慎使用。如果希望立即删除消息而不是重新投递,可以使用basicAck
方法。