EJBs and Transactions
WebLogic's EJB container supports EJBs that can participate in distributed transactions. EJBs deployed to WebLogic Server can be involved in JTA transactions that may cover updates to multiple data stores. A single transaction can span multiple EJBs deployed to multiple WebLogic instances. The EJBs also can participate in the two-phase commit protocol, which coordinates transactional updates across two or more resource managers.
For entity beans, it is the EJB container that always manages the transaction boundaries. Session and message-driven beans support both bean-managed and container-managed transactions. In the case of bean-managed transactions, the EJB implementation must explicitly supervise the transaction boundaries. Typically, the EJB code will acquire a reference to the UserTransaction object from the EJBContext, and then make explicit calls to the begin, commit, and rollback methods to mark the start and completion of the transaction. For container-managed beans, the EJB container manages all transaction boundaries. You can specify the transaction attributes for the EJB methods in the ejb-jar.xml descriptor file for the EJB component. The default transaction setting for an EJB method is Supports. In other words, all EJB methods are capable of participating in a transaction, if one exists. Of course, you must not use the UserTransaction interface within an EJB method that supports container-managed transactions.
10.5.1 Distributed transactions
A client can explicitly wrap multiple EJB calls in a transaction, or invoke an EJB method that implicitly creates a transaction context around method calls to multiple EJBs. The following code snippet shows how you can wrap multiple EJB calls in a JTA transaction:
import javax.transaction.*; UserTransaction tx = null; ... try { tx = (UserTransaction) ctx.lookup("java:comp/UserTransaction"); tx.begin( ); patient1.admit( ); patient2.release( ); patient3.doa( ); tx.commit( ); } catch (Exception e) { tx.rollback( ); }
All the method calls to the Patient entity beans execute as a single, atomic unit, within the context of a client-initiated transaction. This assumes that the EJB methods can execute within a transaction context, so the EJB methods must have a transaction setting of either Required, Supports, or Mandatory. The EJBs involved in the transaction either commit or roll back together, regardless of whether the EJBs are targeted to a single server, multiple servers, or a WebLogic cluster.
Alternatively, you could implement a session bean that wraps calls to multiple entity beans. By assigning a Required transaction setting to the session bean method, you can guarantee that a transaction is available automatically when a client invokes the method. The EJBs involved in the wrapper method also should support transactions, so their transaction setting must be either Required, Supports, or Mandatory. If you have targeted an EJB to a WebLogic cluster, or deployed one across multiple server instances, WebLogic will try to use a copy of the EJB on the same server (if it exists) rather than choose a remote copy of the EJB on another server. Whenever multiple EJBs are involved in a transaction, WebLogic tries to minimize the network traffic for the transaction.
A transaction may need to use EJBs that reside on multiple servers in a WebLogic cluster. This could happen in a heterogeneous cluster, where the EJBs are not deployed uniformly across all members of the cluster. In such cases, WebLogic will create multi-tier JDBC connections to the underlying data source. For optimal performance, you should deploy EJBs uniformly to all members of a WebLogic cluster.
10.5.1.1 Transaction isolation levels
WebLogic extends the JTA by allowing you to set the isolation level for the transaction. The isolation levels determine how concurrent JTA transactions access the underlying data store. The following example shows how a Java application can specify the isolation level for new client-initiated transactions:
import java.sql.Connection import javax.transaction.Transaction; import weblogic.transaction.TxHelper: import weblogic.transaction.Transaction; import weblogic.transaction.TxConstants; UserTransaction tx = (UserTransaction) ctx.lookup("java:comp/UserTransaction"); tx.begin( ); //get transaction associated with this thread Transaction tx = TxHelper.getTransaction( ); //set isolation level to TRANSACTION_READ_COMMITTED tx.setProperty (TxConstants.ISOLATION_LEVEL, new Integer(Connection.TRANSACTION_READ_COMMITTED)); //perform one or more transaction-aware updates tx.commit( );
In this example, we use a WebLogic-specific TxHelper class to obtain the transaction context associated with the current thread. WebLogic then will pass the isolation level to the underlying database (and to other data stores involved as well).
For container-managed transactions, you even can specify the isolation level for EJB methods using the transaction-isolation setting in the weblogic-ejb-jar.xml descriptor file. Once again, the EJB container passes the value of the isolation level to the underlying database. You can choose one of the following values for the isolation level of a transaction:
TRANSACTION_READ_UNCOMMITTED
A transaction may view uncommitted changes made by other transactions.
TRANSACTION_READ_COMMITTED
A transaction may view committed changes made only by other transactions.
TRANSACTION_REPEATABLE_READ
Dirty and nonrepeatable reads are disallowed for any transaction.
TRANSACTION_SERIALIZABLE
This is the most restrictive isolation level, and emulates the serial execution of both transactions.
These values obey the same semantics as the isolation levels that apply to a JDBC connection. The following XML portion from the weblogic-ejb-jar.xml descriptor shows how to set the TRANSACTION_READ_COMMITTED isolation level for all of the EJB's database operations:
PatientEJB ... ... TRANSACTION_READ_COMMITTED PatientEJB Remote *
Both the isolation level and concurrency strategy settings for an EJB component impact the behavior of EJBs when they participate in distributed transactions.