Differences between javax.jms.ConnectionFactory an

2019-05-18 17:59发布

问题:

I'm entering the world of JTA, due to need of distributed transactions, and I'm uncertain about the differences between javax.jms.ConnectionFactory and javax.jms.XAConnectionFactory or more accurately how can it be that javax.jms.ConnectionFactory performed what I expected only javax.jms.XAConnectionFactory can do for me.

The details: I'm using Atomikos essentials as my transaction manager and my app is running on Apache Tomcat 6.

I'm running a small POC with a dummy app where I have my JMS provider (OpenMQ) registered as a JNDI resource.

<Resource name="jms/myConnectionFactory" auth="Container"  
 type="com.atomikos.jms.AtomikosConnectionFactoryBean"  
 factory="com.atomikos.tomcat.EnhancedTomcatAtomikosBeanFactory"   
uniqueResourceName="jms/myConnectionFactory"  
xaConnectionFactoryClassName="com.sun.messaging.XAConnectionFactory"  
maxPoolSize="3"/>

And the strange issue is that in my code I do this:

Context ctx = new InitialContext();  
ConnectionFactory queueConnectionFactory =  
(ConnectionFactory)ctx.lookup("java:comp/env/jms/myQueueFactory");  
javax.jms.Connection connection = queueConnectionFactory.createConnection();  
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);

And later in the code I use this session in a UserTransaction and it performs flawlessly with two MessageProducers with either Commit or Rollback.

What I don't understand is how can it be that I'm using javax.jms.XAConnectionFactory.createConnection() method and I get a Session which does the job? What's javax.jms.XAConnectionFactory role?

I'll also add that I've looked at the source code of both classes (and javax.jms.BasicConnectionFactory) and I verified that the XA class does not override createConnection.

回答1:

The core of the difference between ConnectionFactory and XAConnectionFactory is that the XAConnectionFactory creates XAConnections which create XASessions. XASessions represent the real difference because (to quote from the JMS JavaDocs:)

The XASession interface extends the capability of Session by adding access to a JMS provider's support for the Java Transaction API (JTA) (optional). This support takes the form of a javax.transaction.xa.XAResource object.

In other words, the XASession is what gives the XA instances their transactional awareness. However, this specific implementation is optional, even for a fully compliant JMS provider. From the same JavaDoc:

An XAResource provides some fairly sophisticated facilities for interleaving work on multiple transactions, recovering a list of transactions in progress, and so on. A JTA aware JMS provider must fully implement this functionality. This could be done by using the services of a database that supports XA, or a JMS provider may choose to implement this functionality from scratch. A client of the application server is given what it thinks is a regular JMS Session. Behind the scenes, the application server controls the transaction management of the underlying XASession.

In other words, the provider may require that you specify an XA or non-XA JMS resource, or, as would seem to be in your case, the provider may perform all the JTA plumbing transparently with what appears to be a regular JMS Session.



回答2:

Actually, none of the example code you provided would exercise XA functionality. If all that is required is that your messages are under syncpoint, then you can get by with 1-phase commit (1PC). However if you want, for example, that JMS messages and DB updates occur in a single coordinated unit of work then you would use 2-phase commit (2PC) which is XA. Coordinating across two message producers on the same transport provider does not require XA 2PC.

If you were using 2PC, then in addition to COMMIT and ROLLBACK you would be calling BEGIN somewhere in the code. The lack of that verb in your example is why I said it looks like you are not doing 2PC. The BEGIN call would communicate with the transaction manager to establish a transaction context across the participating resource managers. Then the COMMIT would cause the messages and the DB updates to finalize in one unit of work. The interesting thing here is that if you have only one participating resource manager, some transports will silently optimize you back down to 1PC. In that case it looks as though you are doing 2PC but are really getting 1PC. Since there is only one resource manager there is no loss of reliability in this optimization.

On the other hand, if you are doing 1PC you won't see any difference between the two types of connection factory. It would exhibit exactly the behavior you describe.

The last case to consider is that you use ConnectionFactory and try to call BEGIN. Since the non-XA connection factory cannot participate in a coordinated XA transaction, this call should fail.