消息“秒丢”是因为autoack=true导致rabbitmq立即确认并删除消息;应改为false并手动调用basicack,注意deliverytag来源和异常时的basicnack处理。

VSCode 里跑 RabbitMQ 消费者代码,消息一处理完就消失——不是代码写错了,大概率是 autoAck 被设成了 true,RabbitMQ 根本没等你业务执行完就删了消息。
为什么消息“秒丢”?查 basicConsume 的第三个参数
Java 客户端调用 channel.basicConsume(queueName, autoAck, consumer) 时,第二个参数 autoAck 决定确认模式。设成 true 就是自动确认:RabbitMQ 把消息推给消费者后立刻标记为已确认、从队列移除,不管你的 handleDelivery 里有没有 try-catch、有没有业务逻辑、甚至有没有执行完。
- 现象:日志打印了“接收到消息”,但数据库没更新、下游没触发,且 Web 控制台里
Unacked始终为 0 - 真实原因:消息根本没进“待确认”状态,RabbitMQ 已当它成功消费
- 修复动作:把
basicConsume(..., true, ...)改成basicConsume(..., false, ...)
手动确认必须配 basicAck,且 deliveryTag 别传错
设了 autoAck = false 后,RabbitMQ 会卡住消息,直到你显式调用 channel.basicAck(deliveryTag, multiple)。漏掉这步或参数错,消息就永远停在 Unacked 状态,消费者重启也拿不到(除非连接断开触发重入队)。
-
deliveryTag必须来自handleDelivery方法的envelope.getDeliveryTag(),不能硬编码或复用旧值 -
multiple = false表示只确认当前这条;true表示确认所有小于等于该deliveryTag的未确认消息(慎用,容易误确认) - 常见错误:在异常分支没调用
basicNack或basicReject,导致消息既不确认也不拒绝,堆积在 Unacked
VSCode 调试时别忽略连接/通道生命周期
VSCode 运行 Java 项目时,如果主程序退出(比如 main 方法结束),Connection 和 Channel 会被关闭,而 RabbitMQ 会把所有 Unacked 消息重新入队——你以为消息丢了,其实是被“放回去了”,下次启动又会收到。
- 调试建议:加个
System.in.read()阻塞主线程,避免进程提前退出 - 更稳妥做法:用
try-with-resources或显式channel.close()+connection.close(),并在 shutdown 钩子里处理未确认消息 - 注意:Web 控制台看到的
Ready数量可能滞后,刷新或等几秒才更新
waitForConfirms 是生产者用的,别在消费者里乱调
有些人在消费者代码里看到 channel.waitForConfirms() 就照搬,这是典型混淆角色。这个方法只对生产者有效,用于等待 Broker 对 basicPublish 的确认响应。消费者端调用它会直接抛 IllegalStateException,而且完全不影响消息确认行为。
- 错误示例:
channel.waitForConfirms()放在handleDelivery末尾 → 运行时报错,且无任何确认效果 - 正确归属:生产者发消息后,用它判断是否投递到 Exchange/Queue(配合
confirmSelect()) - 消费者要关注的是
basicAck/basicNack,不是waitForConfirms
最常被忽略的一点:RabbitMQ 的确认机制和消息持久化是两件事。autoAck=false 只保证“消息不因消费者崩溃而丢失”,但如果队列本身没设 durable=true、消息没设 deliveryMode=2,Broker 重启后这些 Unacked 消息照样消失——确认机制管不了磁盘层面的事。











