Connection Enlistment Strategy in GlassFishTHIS IS STILL A DRAFT. SOME CONTENT MAY BE CHANGED Transaction Scenarios.In a Java EE application, transactions can multiple components. The connections used ut1.begin(); Connection con1 = ds.getConnection() con1.createStatement().execute(); Connection con2 = ds.getConnection(); con2.createStatement().execute(); ut1.commit(); The datasource used in the above code snippet is a wrapper above a JDBC driver. So, whenever Now, lets take a little more complex scenario. Connection con1 = ds.getConnection() Connection con2 = ds.getConnection(); ut2.begin(); con1.createStatement().execute(); con2.createStatement().execute(); ut2.commit(); In ut2, the connections are obtained outside the transaction boundary and is used within the transaction. Now, for enlisting such connections, glassfish server runtime does the following. Whenever a connection is obtained, it will be added to a housekeeping datastructure. There is one such datastructure per component. I.e a stateful session bean will have such a datastructure. Whenever transaction starts in the component, the container (EJB container) will make sure that all the connections Component Sharing and its resource list.The object instance (actual EJB bean) doesnt get shared between two transactions. This is because
So, what is the problem?If a session bean A that started the transaction uses a CMP bean. If the CMP bean (The persistence manager behind the bean) obtain a connection in the beforeCompletion method of the transaction synchronization listener, in the absence of __pm, the connection will be associated with the session bean as the beforeCompletion will get executed after the end of CMP method. If the persistence manager does not close the connection in that transaction and reuse it later on for some other CMP, the connection will be available both to the CMP and to the session bean. This can create interesting concurrency issues. Allow-NonComponent-CallersIf your code need to handle the above case, then two things are required. 1. Make sure that you always get the connection within the transaction and return the connection as soon as you do the database/message queue operation. 2. Set the Allow-NonComponent-Callers property in the pool. What does it do?Appserver containers wouldnt keep the connection in the component's resource list, if the connection is obtained from a pool where this property is set. This property is equivalent to the __pm datasource used in older versions of sun application server. Since the connection is not in the component's resource list, there is no concurrency issue. However you cannot expect the connection obtained outside the transaction to be enlisted. Implementation detailsWhen ever a ConnectionFactory (DataSource) is looked up, the JNDI objectfactory will create a new object. The name of the datasource is available to the ObjectFactory. This ObjectFactory creates an appropriate ConnectionManager and saves the name of the datasource in that. From then onwards, whenever ConnectionManager.allocateConnection is executed, the JNDI name is available to the ConnectionManager. The JNDI name is used by the ConnectionManager to get the default resource principal configured in the deployment descriptor, obtain the resource sharing scope etc. It then passes the JNDI name to PoolManager. Important classes.The PoolManagerImpl Could the implementation have taken another path?If a resource adapter supports lazy connection association and lazy connection enlistment, then the connection can be enlisted in the transaction when it is actually used. This will really remove the need for component's resource list. To achieve this, JDBC and JMS resource adapters used in appserver need to support this feature as well. For JDBC resource adapter it will be required to wrap a number of JDBC objects like connection, statement etc. This is something for the later versions of appserver. TODO: Look at how other appserver handle this issue.
|