Chapter 9.  Transactions

Identify correct and incorrect statements or examples about bean-managed transaction demarcation.

[Note]

Support for transactions is an essential element of the Enterprise JavaBeans architecture. The Enterprise Bean Provider and the client application programmer are not exposed to the complexity of distributed transactions. The Bean Provider can choose between using PROGRAMMATIC transaction demarcation in the enterprise bean code (this style is called bean-managed transaction demarcation) or DECLARATIVE transaction demarcation performed automatically by the EJB container (this style is called container-managed transaction demarcation).

With bean-managed transaction (BMT) demarcation, the enterprise BEAN CODE demarcates transactions using the javax.transaction.UserTransaction interface. All resource manager accesses between the UserTransaction.begin and UserTransaction.commit calls are part of a transaction.

The terms resource and resource manager used in this section refer to the resources declared using the Resource annotation in the enterprise bean class or using the resource-ref element in the enterprise bean's deployment descriptor. This includes not only database resources, but also other resources, such as JMS Connections. These resources are considered to be "managed" by the container.

Regardless of whether an enterprise bean uses bean-managed or container-managed transaction demarcation, the burden of implementing transaction management is on the EJB container and server provider. The EJB container and server implement the necessary low-level transaction protocols, such as the two-phase commit protocol between a transaction manager and a database system or messaging provider, transaction context propagation, and distributed two-phase commit.

Client-Managed Demarcation

A Java client can use the javax.transaction.UserTransaction interface to explicitly demarcate transaction boundaries. The client program obtains the javax.transaction.UserTransaction interface through dependency injection or lookup in the bean's EJBContext or in the JNDI name space.

A client program using explicit transaction demarcation may perform, via enterprise beans, atomic updates across multiple databases residing at multiple EJB servers, as illustrated in the following figure:

Updates on Multiple Databases on Multiple Servers

The application programmer demarcates the transaction with beginand commitcalls. If the enterprise beans X and Y are configured to use a client transaction (i.e., their methods have transaction attributes that either require or support an existing transaction context), the EJB server ensures that the updates to databases A and B are made as part of the client's transaction.

Enterprise Beans Using Bean-Managed Transaction Demarcation

The enterprise bean with bean-managed transaction (BMT) demarcation MUST be a session bean OR a message-driven bean.

An instance that starts a transaction must complete the transaction before it starts a new transaction.

The Bean Provider uses the UserTransaction interface to demarcate transactions.

package javax.transaction;
					
public interface UserTransaction {

	void begin() throws NotSupportedException, SystemException;
	
	void commit() throws RollbackException, HeuristicMixedException,
		HeuristicRollbackException, SecurityException,
		IllegalStateException, SystemException;

	void rollback() throws IllegalStateException, SecurityException, SystemException;

	void setRollbackOnly() throws IllegalStateException, SystemException;

	int getStatus() throws SystemException;
	
	void setTransactionTimeout(int seconds) throws SystemException;
}
					

All updates to the resource managers between the UserTransaction.begin() and UserTransaction.commit() methods are performed in a transaction. While an instance is in a transaction, the instance MUST NOT attempt to use the resource-manager specific transaction demarcation API (e.g. it must not invoke the commit or rollback method on the java.sql.Connection interface or on the javax.jms.Session interface). However, use of the Java Persistence API EntityTransaction interface is supported:

@PersistenceContext 
EntityManager em;

@Resource 
UserTransaction tx;

....
tx.begin();
em.persist(new PersistentObject());
tx.commit();
					

or

InitialContext ctx = new InitialContext();
UserTransaction tx = (UserTransaction)ctx.lookup("java:comp/UserTransaction"); // Predefined reserved name
EntityManager em = (EntityManager) ctx.lookup("java:comp/env/persistence/EntityManager");

...
tx.begin();
PersistentObject obj = em.merge(pObj); // merge object to the new context
em.remove(obj);
tx.commit();
					
					

A stateful session bean instance may, but is NOT REQUIRED to, commit a started transaction before a business method returns. If a transaction has not been completed by the end of a business method, the container retains the association between the transaction and the instance across multiple client calls until the instance eventually completes the transaction.

A stateless session bean instance MUST commit a transaction before a business method or timeout callback method returns.

A message-driven bean instance MUST commit a transaction before a message listener method or timeout callback method returns.

The following example illustrates a business method that performs a transaction involving two database connections:

@Stateless
@TransactionManagement(BEAN)
public class MySessionBean implements MySession {
	@Resource javax.transaction.UserTransaction ut;
	@Resource javax.sql.DataSource database1;
	@Resource javax.sql.DataSource database2;
	
	public void someMethod(...) {
		java.sql.Connection con1;
		java.sql.Connection con2;
		java.sql.Statement stmt1;
		java.sql.Statement stmt2;

		// obtain con1 object and set it up for transactions
		con1 = database1.getConnection();
		stmt1 = con1.createStatement();

		// obtain con2 object and set it up for transactions
		con2 = database2.getConnection();
		stmt2 = con2.createStatement();

		//
		// Now do a transaction that involves con1 and con2.
		//
		
		// start the transaction
		ut.begin();
		
		// Do some updates to both con1 and con2. The container
		// automatically enlists con1 and con2 with the transaction.
		stmt1.executeQuery(...);
		stmt1.executeUpdate(...);
		stmt2.executeQuery(...);
		stmt2.executeUpdate(...);
		stmt1.executeUpdate(...);
		stmt2.executeUpdate(...);

		// commit the transaction
		ut.commit();

		// release connections
		stmt1.close();
		stmt2.close();
		con1.close();
		con2.close();
	}
	...
}
					

The following example illustrates a business method that performs a transaction involving both a database connection and a JMS connection:

@Stateless
@TransactionManagement(BEAN)
public class MySessionBean implements MySession {
	@Resource javax.Transaction.UserTransaction ut;
	@Resource javax.sql.DataSource database1;
	@Resource javax.jms.QueueConnectionFactory qcf1;
	@Resource javax.jms.Queue queue1;
		
	public void someMethod(...) {
		java.sql.Connection dcon;
		java.sql.Statement stmt;
		javax.jms.QueueConnection qcon;
		javax.jms.QueueSession qsession;
		javax.jms.QueueSender qsender;
		javax.jms.Message message;
			
		// obtain db conn object and set it up for transactions
		dcon = database1.getConnection();
		stmt = dcon.createStatement();
			
		// obtain jms conn object and set up session for transactions
		qcon = qcf1.createQueueConnection();
		qsession = qcon.createQueueSession(true,0);
		qsender = qsession.createSender(queue1);
		message = qsession.createTextMessage();
		message.setText("some message");

		//
		// Now do a transaction that involves the two connections.
		//

		// 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();
	}
	...
}
					

The following example illustrates a STATEFUL session bean that retains a transaction across three client calls, invoked in the following order: method1, method2, and method3. Note that the Bean Provider must use the pre-passivation callback method here to close the connections and set the instance variables for the connection to null:

@Stateful
@TransactionManagement(BEAN)
public class MySessionBean implements MySession {
	@Resource javax.Transaction.UserTransaction ut;
	@Resource javax.sql.DataSource database1;
	@Resource javax.sql.DataSource database2;
	java.sql.Connection con1;
	java.sql.Connection con2;
	
	public void method1(...) {
		java.sql.Statement stmt;
	
		// start a transaction
		ut.begin();
		
		// make some updates on con1
		con1 = database1.getConnection();
		stmt = con1.createStatement();
		stmt.executeUpdate(...);
		stmt.executeUpdate(...);

		//
		// The container retains the transaction associated with the
		// instance to the next client call (which is method2(...)).
	}
	
	public void method2(...) {
		java.sql.Statement stmt;
		con2 = database2.getConnection();
		stmt = con2.createStatement();
		stmt.executeUpdate(...);
		stmt.executeUpdate(...);
		
		// The container retains the transaction associated with the
		// instance to the next client call (which is method3(...)).
	}
	
	public void method3(...) {
		java.sql.Statement stmt;
		
		// make some more updates on con1 and con2
		stmt = con1.createStatement();
		stmt.executeUpdate(...);
		stmt = con2.createStatement();
		stmt.executeUpdate(...);

		// commit the transaction
		ut.commit();

		// release connections
		stmt.close();
		con1.close();
		con2.close();
	}
	...
}
					

It is possible for an enterprise bean to open and close a database connection in each business method (rather than hold the connection open until the end of transaction). In the following example, if the client executes the sequence of methods (method1, method2, method2, method2, and method3), all the database updates done by the multiple invocations of method2 are performed in the scope of the same transaction, which is the transaction started in method1 and committed in method3:

@Stateful
@TransactionManagement(BEAN)
public class MySessionBean implements MySession {

	@Resource javax.Transaction.UserTransaction ut;
	@Resource javax.sql.DataSource database1;

	public void method1(...) {
		// start a transaction
		ut.begin();
	}

	public void method2(...) {
		java.sql.Connection con;
		java.sql.Statement stmt;

		// open connection
		con = database1.getConnection();
		
		// make some updates on con
		stmt = con.createStatement();
		stmt.executeUpdate(...);
		stmt.executeUpdate(...);
		
		// close the connection
		stmt.close();
		con.close();
	}
	
	public void method3(...) {
		// commit the transaction
		ut.commit();
	}
	...
}
					

getRollbackOnly and setRollbackOnly Methods for BMT Beans

An enterprise bean with bean-managed transaction (BMT) demarcation MUST NOT use the getRollbackOnly and setRollbackOnly methods of the EJBContext interface.

An enterprise bean with bean-managed transaction demarcation has no need to use these methods, because of the following reasons:

  • An enterprise bean with bean-managed transaction (BMT) demarcation can obtain the status of a transaction by using the getStatus method of the javax.transaction.UserTransaction interface.

  • An enterprise bean with bean-managed transaction (BMT) demarcation can rollback a transaction using the rollback method of the javax.transaction.UserTransaction interface.

The container MUST make the javax.transaction.UserTransaction interface available to the enterprise bean's business method, message listener method, interceptor method, or timeout callback method via dependency injection into the enterprise bean class or interceptor class, and through lookup via the javax.ejb.EJBContext interface, and in the JNDI naming context under java:comp/UserTransaction. When an instance uses the javax.transaction.UserTransaction interface to demarcate a transaction, the container must enlist all the resource managers used by the instance between the begin and commit or rollback methods with the transaction. When the instance attempts to commit the transaction, the container is responsible for the global coordination of the transaction commit.

Via JNDI:

Context ctx = new InitialContext( );
UserTransaction ut = (UserTransaction) ctx.lookup("java:comp/UserTransaction");
ut.begin();
...
					

Via EJBContext:

@Resource SessionContext ejbContext;

public void myMethod() {
	try {
		UserTransaction ut = ejbContext.getUserTransaction();
		ut.begin();
		...
					

Via dependency injection:

@Resource UserTransaction ut;

public void myMethod() {
	try {
		ut.begin();
		...
					

In the case of a stateful session bean, it is possible that the business method that started a transaction completes without committing or rolling back the transaction. In such a case, the container must retain the association between the transaction and the instance across multiple client calls until the instance commits or rolls back the transaction. When the client invokes the next business method, the container must invoke the business method (and any applicable interceptor methods for the bean) in this transaction context.

If a stateless session bean instance starts a transaction in a business method or interceptor method, it MUST commit the transaction BEFORE the business method (or all its interceptor methods) returns. The container must detect the case in which a transaction was started, but not completed, in the business method or interceptor method for the business method, and handle it as follows:

  • Log this as an application error to alert the System Administrator.

  • Roll back the started transaction.

  • Discard the instance of the session bean.

  • Throw the javax.ejb.EJBException. If the EJB 2.1 client view is used, the container should throw java.rmi.RemoteException if the client is a remote client, or throw the javax.ejb.EJBException if the client is a local client.

Professional hosting     Belorussian informational portal         Free SCWCD 1.4 Study Guide     Free SCDJWS 1.4 Study Guide     SCDJWS 1.4 Quiz     Free IBM Certified Associate Developer Study Guide     IBM Test 000-287. Enterprise Application Development with IBM WebSphere Studio, V5.0 Study Guide     Free Mock Exam Engine