JMS transactions are how Java applications group messaging operations into units of work that can succeed or fail together on IBM MQ—mirroring the syncpoint concepts COBOL programs express with MQCMIT and MQBACK, but through Session APIs or container-managed JTA. A payment service might get an order message, insert a row in Db2, and put an acknowledgment message; if the insert fails, you want the get rolled back and the acknowledgment never visible—otherwise customers see charged accounts without confirmation or duplicate processing after redelivery. Beginners confuse three layers: acknowledgement mode on a non-transacted session, JMS transacted sessions (local messaging UOW), and global JTA/XA transactions spanning MQ plus a database. This tutorial explains each layer, when commit and rollback run, how IBM MQ maps JMS to syncpoints, interaction with MDB container-managed transactions, pitfalls mixing APIs, performance trade-offs versus saga patterns, and operational recovery when transactions stay indoubt after a server crash.
| Model | Scope | How to commit |
|---|---|---|
| Acknowledgement mode | Single message consume ack | Automatic or message.acknowledge() |
| Transacted session | All ops in one Session | session.commit() / rollback() |
| JTA / XA global | MQ + DB + other RM | Transaction manager commit() |
Pick one primary model per code path. Mixing manual session.commit inside a CMT MDB or calling MQCMIT while enlisted in XA breaks atomicity and creates heuristics operations teams dread.
123456789QueueSession session = connection.createQueueSession(true, 0); // true = transacted; second arg ignored for transacted QueueReceiver receiver = session.createReceiver(queue); Message msg = receiver.receive(); process(msg); // if this throws, call rollback instead of commit session.commit(); // success — syncpoint on IBM MQ // session.rollback(); // failure — uncommitted get/put undone
createQueueSession(true, 0) enables transacted mode; the acknowledgement constant is ignored because the session itself defines the boundary. All sends and receives in that session between commit and rollback belong to one unit of work. Multiple puts to different queues in the same session commit together—useful for fan-out within messaging only, not across databases unless you upgrade to XA.
session.commit() maps to MQ syncpoint commit for the resources that session touched: syncpointed puts become visible to other applications; syncpointed gets are removed permanently from the queue. session.rollback() backs out uncommitted puts and returns uncommitted gets to the queue, incrementing BackoutCount on the message descriptor. This mirrors MQCMIT and MQBACK in MQI terminology. Persistent messages participate according to the same rules as native clients; non-persistent messages may disappear on rollback without disk trace.
Enterprise applications enlist an XA ConnectionFactory in a UserTransaction or @Transactional boundary. The transaction manager runs prepare and commit across IBM MQ and Db2. Spring with JtaTransactionManager and XA-aware DataSource plus XA JMS ConnectionFactory achieves the same when configured correctly. Failure during prepare rolls back all participants. Indoubt transactions after a crash require recovery tools—see the XA transactions tutorial. Do not call session.commit() inside an active JTA transaction unless documentation for your stack explicitly allows it; containers usually forbid double commit.
12345678Typical global flow: @Transactional void handleOrder() { jmsTemplate.convertAndSend("ORD.ACK", "OK"); orderRepository.save(order); } // Spring/JTA commits JMS + DB together on success
Message-Driven Beans with @TransactionAttribute(REQUIRED) wrap onMessage in a container transaction. Success commits JMS get and any enlisted datasources; runtime exceptions roll back. NOT_SUPPORTED suspends transactions for logging-only helpers. Understand which exceptions trigger rollback—checked exceptions may not unless configured. MDB transaction boundaries are the most common place beginners first encounter XA without writing XA code directly.
Transacted sessions and XA add latency versus fire-and-forget NON_PERSISTENT sends. High-throughput telemetry may accept at-most-once delivery. Financial workflows often require XA or the outbox pattern: write business row and outbox event in one database transaction; a separate poller publishes to MQ—avoiding XA cost while keeping consistency through eventual delivery. Sagas compensate with reversal messages instead of atomic commit across services.
A transacted session is paying for groceries and gas in one checkout—if the card fails, neither purchase completes. Acknowledgement modes are like paying for each item at separate registers; one can succeed while another fails.
A transaction is a promise that either everything in the group happens or nothing does. If you put a toy in the cart and your mom says no, you put the toy back—rollback. If she says yes, you keep it—commit.
Map a flow that needs transacted session only versus full XA with a database.
Describe what happens to queue depth when onMessage rolls back repeatedly on the same poison message.
Compare outbox pattern versus XA for a new microservice—list one pro and one con each.
1. session.commit() on transacted session:
2. JTA coordinates:
3. AUTO_ACK is:
4. rollback after get typically: