J2EE Transaction Frameworks: Distributed Transaction Primer
Pages: 1, 2, 3, 4
Transactions in clients: Case I
This is the case where the J2EE configuration is {Stand-alone Client <-> EJB Container <-> RDBMS/EIS Resources}. Transaction support in applets and application clients is not required by the J2EE platform. However, a J2EE product might choose to implement and provide this capability for added value. So the ability of applets and fat standalone application clients to directly access a UserTransaction object depends entirely on the capabilities provided by the container. To ensure portability, applets and application clients should delegate transactional work to the lower tier of enterprise beans.
Transactions in web components: Case II
This is the case where the J2EE configuration is {Browser <->
Web Container <-> RDBMS/EIS Resources}. It is possible for a
servlet or a JSP page to use JNDI lookup to get hold of a
UserTransaction object and use the underlying interface
to programmatically specify transactions. In a two-tier application
configuration where a web component needs to access enterprise
information systems under the scope of a JTA transaction, this is
quite common. The code snippet below illustrates the use of the JTA
interface to specify transactions within a web component:
Context myCntxt = new InitialContext();
UserTransaction ut =
(UserTransaction) myCntxt.lookup("java:comp/UserTransaction");
ut.begin();
// perform transactional work here
ut.commit();
It is important to keep in mind that a web component like a servlet
may only start a transaction in its service
method. Moreover, a transaction started by a servlet or a JSP page
must be completed before the service method returns. Transactions
cannot span across web requests. The following guidelines are
recommended for handling interactions in web components between JTA
transactions, threads, and JDBC connections.
- JTA transactions should start and complete only from the thread in which the service method is called. Additional threads created in the servlet should not attempt to start any JTA transaction.
- JDBC connections may be acquired and released by a thread other than the service method thread, but should not be shared between threads.
- JDBC Connection objects should not be stored in static fields.
- For web components implementing the SingleThreadModel, JDBC Connection objects may be stored in class instance fields.
- For web components (servlets) not implementing the
SingleThreadModel, JDBCConnectionobjects should not be stored in class instance fields and should be acquired and released within the same invocation of theservicemethod.
Transactions in application servers: Case III
This is the case where the J2EE configuration is {Browser <-> Web Container <-> EJB Container <-> RDBMS/EIS Resources}. The following scenarios are illustrated to motivate discussions on use of transactions in application servers with EJB container and a built in transaction monitor.
Scenario A : Messages sent/received over JMS and multiple databases access:
It's possible for an application using EJB servers to send messages to or receive messages from one or more JMS destinations or update data in one or more databases in a single transaction. In the following figure, a client invokes a method on the remote interface of enterprise Bean A. which in turn sends a message to a JMS queue and updates data in a database A. After that, EJB A calls a method of another enterprise Bean B that updates data in database B. The application server with its EJB container and built in transaction manager ensures that the operations on A, B, and C are either all committed or rolled back.
|
The application programmer does not have to do anything to ensure transactional semantics. The EJBs A and B perform the sending of the message and database updates using the standard JMS and JDBC APIs. Behind the scenes, the application server enlists the session on the connection to the JMS provider and the database connections as part of the transaction. When the transaction commits, the application server and the messaging and database systems perform a two-phase commit protocol to ensure atomic updates across all the three resources.
Scenario B: Multiple database access via multiple application servers:
The J2EE architecture allows updates of data at multiple sites to be performed in a single transaction. In the following figure, a client invokes a method on enterprise Bean A. which in turn sends a message to a message queue, updates data in database A. After that, EJB A calls a method in another EJB B deployed in another application server which updates data in database B. The EJB architecture makes it possible to perform the updates to databases A and B in a single transaction.
|
When EJB A invokes EJB B, the two application servers cooperate to propagate the transaction context from A to B. This transaction context propagation is transparent to the application. At commit time, the two application servers use distributed two phase commit protocol (if the capability exists) to ensure the atomicity of the database updates and the transaction.
The two types of transaction demarcation in enterprise beans, namely, bean managed and container managed, are discussed in detail next.
Bean managed transaction
As mentioned before, in a bean-managed transaction, an enterprise
bean uses the javax.transaction.UserTransaction interface
to explicitly specify transaction boundaries in the application
code. Only session beans and message driven beans can choose to use
bean-managed demarcation. An entity bean must always use container
managed transaction demarcation. The following code illustrates the
use of JTA interface to specify transactions in an enterprise bean
with bean-managed transaction demarcation.
UserTransaction ut = ejbContext.getUserTransaction();
ut.begin();
// Transactional work is done here
ut.commit();
The following example illustrates a business method of a typical session bean that performs a bean managed transaction involving both a database connection and a JMS connection.
public class MySessionEJB implements SessionBean {
EJBContext ejbContext;
public void someMethod(...) {
javax.transaction.UserTransaction ut;
javax.sql.DataSource ds;
java.sql.Connection dcon;
java.sql.Statement stmt;
javax.jms.QueueConnectionFactory qcf;
javax.jms.QueueConnection qcon;
javax.jms.Queue q;
javax.jms.QueueSession qsession;
javax.jms.QueueSender qsender;
javax.jms.Message message;
InitialContext initCtx = new InitialContext();
// obtain db conn object and set it up for transactions
ds = (javax.sql.DataSource)
initCtx.lookup("java:comp/env/jdbc/Database");
dcon = ds.getConnection();
stmt = dcon.createStatement();
// obtain jms conn object and set up session for transactions
qcf = (javax.jms.QueueConnectionFactory)
initCtx.lookup("java:comp/env/jms/qConnFactory");
qcon = qcf.createQueueConnection();
qsession = qcon.createQueueSession(true,0);
q = (javax.jms.Queue)
initCtx.lookup("java:comp/env/jms/jmsQueue");
qsender = qsession.createSender(q);
message = qsession.createTextMessage();
message.setText("some message");
//
// Now do a transaction that involves the two connections.
//
ut = ejbContext.getUserTransaction();
// start the transaction
ut.begin();
// Do database updates and send message. The Container
// automatically enlists dcon and qsession with the
// transaction.
stmt.executeQuery(...);
stmt.executeUpdate(...);
stmt.executeUpdate(...);
qsender.send(message);
// commit the transaction
ut.commit();
// release connections
stmt.close();
qsender.close();
qsession.close();
dcon.close();
qcon.close();
}
...
}

