大家好,我是G探险者!
系列文章的第 6 篇,本篇将全面解析 JMS 中的消息确认机制与事务控制,帮助你彻底搞懂 AUTO_ACKNOWLEDGE、CLIENT_ACKNOWLEDGE、DUPS_OK_ACKNOWLEDGE 以及 SESSION_TRANSACTED 之间的区别,以及如何结合 Spring 配置使用。
📌 背景场景
在实际开发中,我们经常看到如下配置:
container.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
也可能看到:
container.setSessionTransacted(true);
很多开发者混淆了它们的含义和关系,甚至错误地以为:
“开启事务,就不用管 ACK 了”
“用了 Spring 容器,它会自动 commit”
这些误解会导致 消息重复处理、消息丢失 等隐性 bug。
✅ 一、JMS 消息确认模式有哪些?
JMS 定义了以下 4 种消息确认模式:
| 模式常量 | 含义 | 说明 |
|---|---|---|
AUTO_ACKNOWLEDGE | 自动确认 | ✅ 默认模式。消息处理完成后自动确认 |
CLIENT_ACKNOWLEDGE | 客户端手动确认 | 开发者需手动调用 message.acknowledge() |
DUPS_OK_ACKNOWLEDGE | 允许重复的懒惰确认 | 性能更好,但可能重复消费 |
SESSION_TRANSACTED | 事务性确认 | ✅ 推荐配合 setSessionTransacted(true) 使用,自动 commit/rollback |
🧠 二、ACK 模式和事务的关系图
┌──────────────────────────────┐
│ Session │
├─────────────┬────────────────┤
│ Transacted? │ Ack Mode │
├─────────────┼────────────────┤
│ false │ AUTO_ACK │ 消息处理后自动 ack(推荐) ✅
│ false │ CLIENT_ACK │ 需手动 ack,适合幂等处理 ⚠️
│ false │ DUPS_OK_ACK │ 性能好但可能重复 ❗
│ true │ ignored │ 使用事务,commit/rollback ✅
└─────────────┴────────────────┘
🚨 只要开启了事务
setSessionTransacted(true),ack 模式就会被忽略,交由 commit/rollback 控制。
📘 三、各模式详解与使用建议
1. AUTO_ACKNOWLEDGE(自动确认)
container.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
- Spring 自动在消息成功处理后调用
ack - 如果
onMessage()抛出异常,消息不会自动 ack - 适用于大部分无事务业务
✅ 推荐使用(只要不需要事务)
2. CLIENT_ACKNOWLEDGE(客户端确认)
container.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
-
开发者自己控制 ack 时机:
public void onMessage(Message message) { // 业务处理完成后手动确认 message.acknowledge(); } -
⚠️ 如果忘了调用
acknowledge(),MQ 会重复投递
📌 适用于需要多条消息聚合处理时再一起确认的场景
3. DUPS_OK_ACKNOWLEDGE(允许重复确认)
container.setSessionAcknowledgeMode(Session.DUPS_OK_ACKNOWLEDGE);
- 容器可能批量延迟 ack,提升吞吐量
- MQ 有可能重复投递同一条消息(非幂等不建议)
⚠️ 慎用,适用于高吞吐但容忍重复的场景
4. SESSION_TRANSACTED(事务模式)
使用事务的方式如下:
container.setSessionTransacted(true);
container.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED);
onMessage()抛异常 → 自动rollback- 消息会重新进入队列
- ✅ 推荐用于关键业务 + MQ 重试机制 + 幂等设计
🛠️ 四、实际行为对照表(结合 Spring 容器)
| 设置 | 自动确认 | 抛异常会重试? | 幂等性建议 |
|---|---|---|---|
AUTO_ACK | ✅ 是 | ✅ 会重投 | ✅ 推荐 |
CLIENT_ACK | ❌ 需手动 | ❌ 不会自动重投 | ⚠️ 适合手动控制 |
DUPS_OK_ACK | ✅ 延迟确认 | ✅ 会重投 | ❗ 慎用 |
SESSION_TRANSACTED + 事务 | 自动 commit/rollback | ✅ 会重试 | ✅ 强烈推荐 |
☑️ 五、实战开发建议
| 业务场景 | 推荐配置 |
|---|---|
| 普通非事务处理 | AUTO_ACKNOWLEDGE |
| 高可靠、需重投 | SESSION_TRANSACTED + 事务监听 |
| 批量手动 ack | CLIENT_ACKNOWLEDGE |
| 高吞吐允许重复 | DUPS_OK_ACKNOWLEDGE |
| 和事务集成 | 配合 @Transactional 使用(Spring 框架级) |
⚠️ 六、开发中常见误区
| 误区 | 正解 |
|---|---|
| 用了事务就不管 ack 了? | ✅ 对的,ack 被事务接管 |
忘记调用 message.acknowledge() 会怎样? | 消息会重新投递(重复) |
onMessage() 异常就等于 MQ 会重试? | 仅在事务模式下是,其他 ack 模式未必会 |
📘 下一篇预告:
第 7 篇:《JMS 高可用集群配置详解:IBM MQ 与 TongLinkQ 的自动重连机制对比》
我们将深入对比 TongLinkQ 与 IBM MQ 的连接重连机制,配置方式、Spring 中的支持程度,以及如何构建稳定的 MQ 高可用环境。