If the session is transacted, the acknowledgeMode
is ignored. That's why a new single-argument createSession(int)
was added in JMS 2.0 to make it more intuitive. So there's no such thing as "transacted session in auto-acknowledge mode". You either have a transacted or a auto-acknowledged session. Calls to Message.acknowledge()
in a transacted session are ignored (it's specified by the JMS API).
So what's the difference? It's not whether you use one or multiple destinations, as multiple places on the internet claim (including the other answer here). It depends on whether the session is consume-only or consume-produce. If it's consume-only (you don't produce any messages), then both modes are equal: calling either Message.acknowledge()
or Session.commit()
acknowledges all the messages received in the session. Even if received from multiple queues.
Behavior for consume-produce sessions:
client-acknowledge: sent messages are committed as soon as the MessageProducer.send()
method returns. Client messages are acknowledged all at once when Message.acknowledge()
is called. This is not specifically mentioned in the specs, but I think if the broker fails after acking half of the msgs, the client will report an error and only a part of the messages will remain acked. This gives you at-least-once guarantee: if you ack at the end of your process and your program fails mid-way, the output messages will be produced twice.
transactional: sent messages are committed atomically together with acknowledging all received messages in the session. No failure on the client or broker side can cause that just a part of the messages is produced or acked. This gives you exactly-once processing guarantee. It's even faster: as claimed here or here, if you produce multiple messages in one transaction, the MessageProducer.send()
method will be async and the commit()
method will wait for all sends to finish in a batch.