Exactly-once delivery sounds like the perfect promise: every business event happens once, never skipped, never doubled. IBM MQ is excellent at not losing persistent messages and at redelivering when consumers fail—but that strength naturally produces at-least-once behavior unless you design above the queue manager. Vendors and slide decks sometimes say MQ delivers exactly-once; architects know the honest story is exactly-once processing is an application and data problem built on reliable messaging. This page defines the semantics, shows failure timelines where duplicates appear, explains idempotency keys and MsgId deduplication, contrasts with Kafka and database transactions, and gives MQ patterns beginners can implement in a lab without pretending the queue manager alone deduplicates your payroll.
| Semantic | Meaning | Typical MQ role |
|---|---|---|
| At-most-once | Message may be lost; usually not redelivered | |
| At-least-once | No loss under rules; duplicates possible | |
| Exactly-once | Business effect once despite duplicates |
Consider a consumer that MQGETs a persistent message under syncpoint, writes to a database, then crashes before MQCMIT. The message returns to the queue (or remains available for redelivery depending on get options and backout count). A second instance gets the same message again. MQ did its job—no silent loss. Your order service might ship two parcels unless charge logic checks whether OrderId 8842 was already fulfilled. Exactly-once processing means the second delivery does not double-charge or double-ship even though MQ delivered twice.
Exactly-once processing at step 6 detects order 8842 already shipped (natural key) or recognizes MsgId already in PROCESSED_MSG table, and commits MQ without repeating side effects.
MsgId uniquely identifies a message instance on the queue manager (applications can set it for request-reply matching). CorrelId links replies to requests. For deduplication, many teams store MsgId plus PutDate or a hash of the payload. Be careful resetting MsgId on republish—that creates a new identity and bypasses dedup. Expiry and report options do not replace idempotent design.
MQCMIT under global transaction coordinates MQ with Db2, Oracle, or other XA resources so either all commit or all roll back. That is atomicity, not exactly-once across time. After successful commit, a later duplicate delivery is still possible if a downstream system republishes or if a duplicate message was put at the producer. Teach your team: syncpoint prevents torn updates inside one unit of work; idempotency handles redelivery across units of work.
Single-threaded consumer, no syncpoint, auto-commit get—might process once in the happy path but loses messages on failure (drifting toward at-most-once). Kafka exactly-once streams use broker transactions and consumer offsets in specialized setups; MQ integrators achieve similar goals with different primitives. Document your estate honestly in architecture decision records: MQ provides durable at-least-once; services implement exactly-once business semantics.
12345-- After MQGET under syncpoint, before side effects: -- INSERT INTO processed_messages (msg_id, processed_at) -- VALUES (:MsgIdFromMQMD, CURRENT_TIMESTAMP); -- If unique violation -> duplicate delivery -> skip business logic, MQCMIT anyway -- If insert ok -> run business logic -> MQCMIT with DB + MQ in same UoW when using XA
The teacher might read your homework request twice because the first time the classroom door slammed (crash). Exactly-once means you only write one answer in your notebook even if you hear the question twice—you check if you already did homework for that worksheet number before starting again.
Non-persistent metrics, no syncpoint, auto-commit get. Which semantics apply for transport and for business processing?
Payment messages carry client idempotency key PAY-abc-123. Sketch tables and commit order with MQGET syncpoint.
Rewrite the marketing claim MQ guarantees exactly-once into accurate architecture language for compliance reviewers.
1. IBM MQ under failure typically gives consumers:
2. A consumer crashes after updating the database but before MQCMIT. On restart:
3. Storing processed MsgIds in a table is an example of:
4. Exactly-once processing usually requires: