Show Table of Contents
7.4. XA Client with Two Connections to a Broker
A special case arises where an XA client opens two separate connections to the same remote broker instance. You might want to open two connections, for example, in order to send messages to the broker with different properties and qualities of service.
Each XA connection is implicitly associated with its own dedicated XA resource object. When two XA resource objects are equivalent (as determined by calling
XAResource.isSameRM), however, many Transaction Managers treat these XA resource objects in a special way: when the current transaction finishes (committed or rolled back), the Transaction Manager calls
XAResource.endonly on the first enlisted
XAResourceinstance. This creates a problem for Apache ActiveMQ, which expects
XAResource.endto be called on every enlisted
XAResourceinstance. To avoid this problem, Apache ActiveMQ provides an option which forces the Transaction Manager to call
XAResource.endon every XA resource instance.
To cope with the scenario where an XA client opens two connections to the same remote broker, it is normally necessary to set the
true. The effect of setting this option to
trueis that XA resource names are then based on the connection ID, instead of being based on the broker ID. This ensures that all connections have distinct XA resource names, even if they are connected to the same broker instance (note that every connection is associated with its own XA resource object). A side effect of setting this option is that the Transaction Manager is guaranteed to call
XAResource.endon each of the XA resource objects.
When you set the
true, the transaction manager adopts the 2-phase commit protocol (2-PC). Hence, there is a significant overhead associated with sending messages on one connection and receiving messages on another, when transactions are enabled.
Setting rmIdFromConnectionId option on an endpoint URI
You can enable the
rmIdFromConnectionIdoption by setting
trueon an Apache ActiveMQ endpoint URI. For example, to enable this option on an OpenWire URI:
Setting rmIdFromConnectionId option directly on ActiveMQXAConnectionFactory
You can enable the
rmIdFromConnectionIdoption directly on the
ActiveMQXAConnectionFactoryclass, by invoking the
setRmIdFromConnectionIdmethod. For example, you can set the
rmIdFromConnectionIdoption in Java, as follows:
// Java ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory( ... ); cf.setRmIdFromConnectionId(true);
And you can set the
rmIdFromConnectionIdoption in XML, as follows:
<!-- ActiveMQ XA Resource Manager --> <bean id="resourceManager" class="org.apache.activemq.pool.ActiveMQResourceManager" init-method="recoverResource"> <property name="transactionManager" ref="recoverableTxManager"> <property name="connectionFactory" ref="jmsXaConnectionFactory"> <property name="resourceName" value="activemq.default"> <property name="rmIdFromConnectionId" value="true"> </bean>
Example using rmIdFromConnectionId
The following example shows you how to use the
rmIdFromConnectionIdoption in the context of an XA aware JMS client written in Java:
// Java import org.apache.activemq.ActiveMQXAConnectionFactory import javax.jms.XAConnection; import javax.jms.XASession; import javax.jms.XATopicConnection; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; ... ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory("tcp://brokerhost:61616?jms.rmIdFromConnectionId=true"); ... // Configure other connection factory options (not shown) XAConnection connection1 = (XAConnection)cf.createConnection(); XASession session1 = connection1.createXASession(); XAResource resource1 = session1.getXAResource(); XAConnection connection2 = (XAConnection)cf.createConnection(); XASession session2 = connection2.createXASession(); XAResource resource2 = session2.getXAResource(); ... // Send messages using 'connection1' AND connection2' in this thread ... // Commit transaction => transaction manager sends xa.end() to BOTH XAResource objects
In this case, the XA transaction proceeds as follows:
- Because this is an XA example, it does not show any explicit transaction demarcation (for example,
commitinvocations). In this case, the XA Transaction Manager (TM) is responsible for transaction demarcation. For example, if you were deploying this code into a container that supports transactions, the container would normally be responsible for transaction demarcation.
- When you create the first
connection1, it automatically creates the associated
XAResourceobject for this connection,
resource1. The TM automatically enlists
resource1into the current transaction by calling XAResource.start().
- Because you have set
truein this example,
resource2have different XA resource names, which means that the TM treats them as two different resources.
- You can now do some work in the current transaction by sending messages on
connection2. All of these message sends belong to the current transaction.
- When the current transaction is finished (committed or rolled back), the TM will call XAResource.end() on both
resource2. This behaviour is guaranteed, because the TM perceives
resource2to be different resources (due to different XA resource names).NoteIf you have not set the
rmIdFromConnectionIdoption, the typical behaviour of the TM at this point would be to call
XAResource.endonly on the first resource,
resource1. This creates problems in the context of Apache ActiveMQ, because the second connection,
connection2, can send messages asynchronously and these asynchronous messages will not be synchronized with the transaction unless the TM calls