WebLogic Server provides a transaction service that allows J2EE applications to manage their own transaction boundaries. WebLogic's transaction service supports multithreaded clients i.e., a client can make concurrent requests for transactions in multiple threads. WebLogic Server implements flat transactions, which means that multiple transactions cannot be associated with the same thread at the same time. WebLogic supports distributed transactions that may span multiple WebLogic servers, clusters, and even domains.
The EJB container uses WebLogic's transaction service to coordinate transactions across EJB components. EJBs that support bean-managed transactions and J2EE applications both use the JTA to explicitly manage their own transactions. J2EE clients can obtain the UserTransaction and TransactionManager objects from the JNDI tree and use these interfaces to demarcate their transaction boundaries. This allows lightweight clients to begin and commit transactions, and delegate the actual responsibility of coordinating the transaction to the remote transaction manager running on WebLogic Server.
6.3.1 Using JTA Transactions
The JTA defines the contract between the transaction manager and all resources involved in a distributed transaction i.e., the application, the application server, and the resource manager. It allows you to coordinate updates to multiple resources in a safe, elegant way, regardless of the transaction manager. The transaction manager is the standard façade to the transaction service. It manages the transaction boundaries on behalf of the J2EE applications. Ideally, a J2EE application should use the javax.transaction.UserTransaction interface to create a new transaction context. You can use the JTA transactions from within a J2EE client application or a server-side component, such as a servlet, a JMS message consumer, or any EJB that supports bean-managed transactions.
Here's an example that illustrates how you can use JTA transactions from within a servlet:
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { Connection con = null; Statement st = null; UserTransaction tx = null; try { InitialContext ic = new InitialContext( ); //get reference to XA-aware data source(s) from JNDI tree DataSource db1 = ic.lookup("java:comp/env/jdbc/xads1"); DataSource db2 = ic.lookup("java:comp/env/jdbc/xads2"); tx = (UserTransaction) ic.lookup("java:comp/UserTransaction"); tx.begin( ); //start a new transaction //update some table in db1 con = db1.getConnection( ); st = con.createStatement( ); st.executeUpdate("update foo ..."); st.close( ); //update some table in db2 con2 = db2.getConnection( ); st = con2.createStatement( ); st.executeUpdate("delete from foobar ..."); st.close( ); tx.commit( ); //commit all changes //indicate success to client browser } catch (Exception e) { if (tx != null) tx.rollback( ); //rollback current transaction throw new ServletException(e); } finally { //release all db resources try { if (con != null) con.close( ); if (con2 != null) con2.close( ); } catch (Exception ignored) {} } }
Unlike with EJBs, where you can use the EJBContext object to acquire a UserTransaction object, a servlet needs to look it up in the JNDI tree. WebLogic Server makes the UserTransaction object available to all application components in the JNDI tree under java:comp/UserTransaction. You then can invoke the begin( ) method to initiate a transaction, and later the commit( ) method to indicate that all updates may be committed. If an error occurs during the lifetime of the transaction, you can invoke the rollback( ) method to indicate that the transaction must be aborted.
If an external client uses JTA transactions, the only change is in the way you obtain the UserTransaction object:
Context ctx = null; Hashtable env = new Hashtable( ); env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); env.put(Context.PROVIDER_URL, "t3://localhost:7001"); env.put(Context.SECURITY_PRINCIPAL, "joebloggs"); env.put(Context.SECURITY_CREDENTIALS, "somepassword"); ctx = new InitialContext(env); UserTransaction tx = (UserTransaction) ctx.lookup("javax.transaction.UserTransaction");
This code sample shows how an external client needs to provide additional information, such as the T3 URL of a running server, and details of the WebLogic principal who is authorized to access the specified branch of the JNDI tree. For an external client, WebLogic Server makes the UserTransaction object available in the JNDI tree under javax.transaction.UserTransaction.
6.3.2 Using XA Versus Non-XA Drivers in JTA Transactions
Recall how a JDBC connection pool can be configured using either an XA-aware JDBC driver or a non-XA driver. If an XA-aware driver is used, the XA-aware data source associated with this connection pool can participate fully in distributed transactions. If the connection pool has been configured using a non-XA JDBC driver, the associated data source can still participate in JTA transactions, provided you instruct WebLogic to emulate two-phase commit for the data source. Thus, an XA-aware data source configured using a pool of non-XA connections can honor distributed transactions only if you've enabled two-phase commit emulation on the data source. You do have to pay a price for this emulation, though.
First, WebLogic manages connections from a non-XA driver and an XA-aware driver in different ways. When a non-XA connection is involved in a distributed transaction, WebLogic holds onto the physical JDBC connection for the duration of the transaction until it is committed or rolled back. Thus, for a non-XA pool, the number of concurrent transactions is limited by the size of the connection pool. XA connections, on the other hand, are more flexible. In this case, WebLogic doesn't need to hold onto the physical JDBC connection until the transaction completes. Clearly, an XA pool is more scalable because the number of active transactions isn't limited by the size of the pool.
Second, a distributed transaction can handle only one XA-aware data source configured for two-phase commit emulation. This means that WebLogic cannot manage multiple XA-aware data sources enabled with the two-phase commit emulation within the same JTA transaction. If you attempt to enlist non-XA connections obtained from two (or more) XA-aware data sources configured for two-phase commit emulation within a JTA transaction, WebLogic will throw an SQLException.
You must adhere to some programming guidelines when using a XA-aware data source:
Finally, if the XA-aware data source is configured to use a non-XA pool of connections, the connection obtained from the data source will be enlisted in a distributed transaction only if you obtain the connection after the transaction has been initiated. Thus, for any XA-aware data source using two-phase commit emulation, you should request a connection from the data source only after beginning a new transaction context:
InitialContext ctx = new InitialContext( ); //get reference to XA-aware data source from JNDI tree DataSource ds = ic.lookup("java:comp/env/jdbc/txds"); tx = (UserTransaction) ic.lookup("java:comp/UserTransaction"); tx.begin( ); //start a new transaction //now create a connection so that it can be enlisted in the transaction Connection con = ds.getConnection( ); ...
However, if the XA-aware data source has been configured using an XA-aware JDBC driver, it makes no difference whether you acquire the Connection object before or after the JTA transaction has been initiated. Also, ensure that you close an XA connection after the transaction has been committed. In fact, we recommend that you create and release XA connections from outside the scope of a transaction context. This way, an XA connection is enlisted for the duration of the JTA transaction, until it has been committed.
6.3.2.1 Data integrity problems with two-phase commit emulation
You should use two-phase commit emulation with caution because it is not a perfect strategy and can result in some data integrity problems. Two-phase commit emulation is designed to ensure that the non-XA connection always succeeds in the prepare phase of the distribution transaction. The local transaction on the non-XA connection commits only when all other XA-aware resources involved in the distributed transaction are ready to commit. Only when this commit on the non-XA connection succeeds does the overall distributed transaction commit its work. If any of the other XA-aware resources involved in the transaction need to roll back, the overall distributed transaction as well as the local transaction on the non-XA connection also roll back.
If the commit or rollback on the local transaction fails, a heuristic error results, which may lead to data integrity errors. A similar error can occur if, say, a network error occurs after a commit message has been sent to all XA resources in the distributed transaction. The transaction manager will automatically abort the commit on all participating resources, but the non-XA resource will have committed its work, thereby resulting in a heuristic completion. For these reasons, ensure that your applications can tolerate potential heuristic completions when using an XA-aware data source configured for two-phase commit emulation.
6.3.3 WebLogic Extensions to the JTA
The JTA defines the following interfaces:
WebLogic Server extends the capabilities of the JTA interfaces in the following ways:
Refer to the API documentation for a more detailed explanation of these extensions.
Introduction
Web Applications
Managing the Web Server
Using JNDI and RMI
JDBC
Transactions
J2EE Connectors
JMS
JavaMail
Using EJBs
Using CMP and EJB QL
Packaging and Deployment
Managing Domains
Clustering
Performance, Monitoring, and Tuning
SSL
Security
XML
Web Services
JMX
Logging and Internationalization
SNMP