|
|
Transactions and the WebLogic Enterprise JDBC/XA Driver
This topic includes the following sections:
This topic describes how to integrate transactions with CORBA Java, EJB, and RMI applications that use the WebLogic Enterprise JDBC/XA driver and run under BEA WebLogic Enterprise. Before you begin, you should read Introducing Transactions.
Before You Begin
This chapter describes handling transactions in CORBA Java, EJB, and RMI applications that use the WebLogic Enterprise JDBC/XA driver to connect to resources.
For EJB applications, the information in this document supplements the Enterprise JavaBeans Specification 1.1 published by Sun Microsystems, Inc. For general information about implementing Enterprise JavaBeans in WebLogic Enterprise applications, see "Developing WebLogic Enterprise EJB Applications" in Getting Started.
About Transactions and the WebLogic Enterprise JDBX/XA Driver
This topic includes the following sections:
Support for Transactions Using the WebLogic Enterprise JDBC/XA Driver
WebLogic Enterprise provides a multithreaded JDBC/XA driver for Oracle Corporation's Oracle8i database management system. The WebLogic Enterprise JDBC/XA driver fully supports XA, the bidirectional system-level interface between a transaction manager and a resource manager of the X/Open Distributed Transaction Processing (DTP) model. This driver is available to CORBA Java, EJB, and RMI applications and runs in the WebLogic Enterprise environment only.
Pooled Connections
Java applications use the WebLogic Enterprise JDBC/XA driver to establish concurrent connections to multiple Oracle8i databases via their associated resource managers. For distributed transactions, applications must obtain database connections from the JDBC connection pool. (However, this is not a requirement for other jdbcKona drivers in local transaction mode or for third-party drivers.) Thereafter, applications perform database operations using standard JDBC API calls.
A JDBC connection is governed by the pooled connection lifecycle in the JDBC connection pool. As such, the application server might implicitly close JDBC/XA connections to enforce certain personality-specific transactional resource restrictions, as described in JDBC Accessibility in Java Methods. For more information about using WebLogic Enterprise JDBC connection pools with WebLogic Enterprise JDBC/XA driver, see "Using JDBC Connection Pooling" in Using the JDBC Drivers.
Characteristics of JavaServerXA
The JavaServerXA server hosts the WebLogic Enterprise JDBC/XA driver. The JavaServerXA has the following characteristics:
WebLogic Enterprise fully supports the JDBC 1.22 API (core functionality), the JDBC 2.0 Core API, and the distributed transactions (the javax.sql.DataSource API), connection pooling, and JNDI capabilities in the JDBC 2.0 Optional Package API. See Using the JDBC Drivers for a complete list of WebLogic Enterprise-supported JDBC 2.0 features.
Local Versus Distributed (Global) Transactions
WebLogic Enterprise applications using the WebLogic Enterprise JDBC/XA driver can perform local transactions as well as distributed (also called global) transactions. A local transaction involves updates to a single resource manager (such as a database), while a distributed transaction involves updates across multiple resource managers.
The WebLogic Enterprise JDBC/XA driver never starts a local transaction on behalf of an application. However, if the application performs database operations without first explicitly starting a distributed transaction, then these database operations occur within an "unspecified transaction context" and WebLogic Enterprise delegates the responsibility of handling this situation to the database.
In Oracle8i, for example, the database might start a local transaction to perform such database operations.
Failure to commit a local transaction may result in XAER_OUTSIDE error (indicating that the resource manager is performing work outside a distributed transaction) on subsequent distributed transaction operations, which includes beginning a distributed transaction. It is the responsibility of the application to be aware of the transaction context at any point and to complete distributed or local transactions appropriately.
Differences Between Local and Distributed Transactions
Table 7-1 lists differences between local and distributed transactions.
Category |
Local Transactions |
Distributed Transactions |
---|---|---|
Resource Managers/Databases |
Single database / resource manager |
Can span across multiple resource managers |
Transaction Demarcation API |
Can use the following API: java.sql.Connection |
Can use either of following APIs: CORBA API EJB API: javax.transaction |
Autocommit |
Can be enabled or disabled |
Must be disabled |
Configuring the ENABLEXA Parameter in the UBBCONFIG
To use the WebLogic Enterprise JDBC/XA driver, you must specify the ENABLEXA parameter (ENABLEXA=Y) in the JDBCCONNPOOLS section of the UBBCONFIG, as shown in Listing 7-1. In this example, distributed transactions are enabled for the bank_pool connection pool.
Note: This setting applies only to the WebLogic Enterprise JDBC/XA driver.
Listing 7-1 Specifying JDBCCONNPOOLS Information in UBBCONFIG
JDBCCONNPOOLS
bank_pool
SRVGRP = BANK_GROUP1
SRVID = 2
DRIVER = "weblogic.jdbc20.oci815.Driver"
URL = "jdbc:weblogic:oracle:Beq-local"
PROPS = "user=scott;password=tiger;server=Beq-Local"
ENABLEXA = Y
INITCAPACITY = 2
MAXCAPACITY = 10
CAPACITYINCR = 1
CREATEONSTARTUP = Y
For more information about configuring JDBC connection pools, see "Using JDBC Connection Pooling" in Using the JDBC Drivers.
Demarcating Transaction Boundaries for Local and Distributed Transaction Contexts
Applications must carefully and explicitly demarcate transaction boundaries between distributed and local transaction contexts. For example, when an application uses the WebLogic Enterprise JDBC/XA driver to connect to a database:
After completing local transactions, the application must then disable autocommit before beginning a new distributed transaction. Listing 7-2 provides a simple example to illustrate switching between a distributed and local transaction.
Listing 7-2 Switching Between Distributed and Local Transactions
// Assumes that javax.transaction.UserTransaction (tx) and
// java.sql.Connection (con) were initialized previously
// Begin a distributed transaction
System.out.println("Beginning distributed transaction...");
tx.begin();
// Database operations within scope of transaction tx
if(gotException){
try{
tx.rollback();
System.out.println("rolled back transaction");
}catch(Exception e){}
}
elseif{
tx.commit();
System.out.println("committed transaction");
}
// Local transactions
conn.setAutoCommit(true)
...[Database operations]...
conn.setAutoCommit(false)
// Begin another distributed transaction
System.out.println("Beginning distributed transaction...");
tx.begin();
...
Transaction Contexts in WebLogic Enterprise JDBC/XA Connections
For WebLogic Enterprise JDBC/XA connections, database operations will always be performed in the current transaction context. For example, an application might obtain a JDBC/XA connection in a NULL transaction context, begin a distributed transaction, and then perform database operations using that connection. These database operations will be performed in the context of the current distributed transaction.
Applications use WebLogic Enterprise JDBC/XA connection API in the same way as other jdbcKona connections except that, while within a distributed transaction context:
Listing 7-3 shows, in a sample CORBA Java application, how to determine the current transaction context and commit a local or global transaction accordingly.
Listing 7-3 Determining Whether the Application Is in a Distributed Transaction
// Assumes that org.omg.CosTransactions.Current (tc) and
// java.sql.Connection (con) were initialized before
// database operations were attempted
if (tc.get_status() != org.omg.CosTransactions.Status.StatusNoTransaction)
{
// Application is currently in a distributed transaction
tc.commit(true);
}
else
{
// Application is currently in a local transaction
con.commit();
}
Similarly, for bean-managed transactions in an EJB application, the application can determine whether the application is currently in a distributed transaction by calling the UserTransaction.getStatus() method and testing for a returned STATUS_NO_TRANSACTION.
JDBC Accessibility in Java Methods
This topic includes the following sections:
Note: Attempting to use a WebLogic Enterprise JDBC/XA connection in a method where it is not supported may have undefined behavior and possibly raise a SQLException.
JDBC/XA Accessibility in CORBA Methods
Table 7-2 lists which methods in CORBA methods can access JDBC/XA connections.
Server Method |
Accessibility |
---|---|
Constructor |
Not supported |
initialize |
Supported, after open_xa_rm |
activate_obj |
Supported |
deactivate_obj |
Supported |
Business method |
Supported |
release |
Supported, before close_xa_rm |
After completing the initialize method, WebLogic Enterprise automatically closes any open connections and writes a warning message to the ULOG.
For transaction-bound and process-bound objects, the CORBA framework allows open connections to be retained at method end, and the transaction context of the retained connections will be as described in Transaction Contexts in WebLogic Enterprise JDBC/XA Connections upon subsequent method invocations. However, for method-bound objects, applications must explicitly close open connections before method end. If not, WebLogic Enterprise automatically closes any open connections and writes a warning message to the ULOG.
JDBC/XA Accessibility in EJB Methods
For EJB methods, accessibility to JDBC/XA connections varies depending on the EJB type. For details about retaining JDBC/XA connections across method invocations (for stateful session beans only), including examples, see Section 11.3.3 in the Enterprise JavaBeans Specification 1.1, published by Sun Microsystems, Inc.
Note: For all bean types, after completing the ejbCreate method, WebLogic Enterprise automatically closes any open connections and writes a warning message to the ULOG.
Stateful Session Beans
Table 7-3 lists which stateful session bean methods can access JDBC/XA connections.
Bean Method |
Container-managed Transaction |
Bean-managed Transaction |
---|---|---|
Constructor |
Not supported |
Not supported |
setSessionContext |
Not supported |
Not supported |
ejbCreate ejbRemove ejbActivate ejbPassivate |
Supported, but in unspecified transaction context (as defined in the Enterprise JavaBeans 1.1 specification) |
Supported, but in unspecified transaction context (as defined in the Enterprise JavaBeans 1.1 specification), unless the bean explicitly begins a transaction using UserTransaction |
Business method |
Supported |
Supported |
afterBegin |
Supported |
N/A |
beforeCompletion |
Supported |
N/A |
afterCompletion |
Supported |
N/A |
For stateful session beans, the Bean Provider must close all JDBC connections in ejbPassivate and assign the instance's fields storing the connections to null. However, after completing the ejbPassivate method, WebLogic Enterprise automatically closes any open connections and writes a warning message to the ULOG.
Stateless Session Beans
Table 7-4 lists which stateless session bean methods can access JDBC/XA connections.
Bean Method |
Container-managed Transaction |
Bean-managed Transaction |
---|---|---|
Constructor |
Not supported |
Not supported |
setSessionContext |
Not supported |
Not supported |
ejbCreate |
Not supported |
Not supported |
ejbRemove |
Not supported |
Not supported |
Business method |
Supported |
Supported |
Note: For stateless session beans, after completing a business method, WebLogic Enterprise automatically closes any open connections and writes a warning message to the ULOG.
Entity Beans
Table 7-5 lists which entity bean methods can access JDBC/XA connections.
Bean Method |
Accessibility |
---|---|
Constructor |
Not supported |
setEntityContext |
Not supported |
unsetEntityContext |
Not supported |
ejbCreate |
Supported |
ejbPostCreate |
Supported |
ejbRemove |
Supported |
ejbFind |
Supported |
ejbActivate |
Not supported |
ejbPassivate |
Not supported |
ejbLoad |
Supported |
ejbStore |
Supported |
business method |
Supported |
Using the JDBC/XA Driver
Before applications can use the WebLogic Enterprise JDBC/XA driver, the JDBC/XA driver must be integrated into your development environment by completing the following steps:
Listing 7-4 OPENINFO Setting in Sample UBBCONFIG
*GROUPS
SYS_GRP
LMID = SITE1
GRPNO = 1
BANK_GROUP1
LMID = SITE1
GRPNO = 2
OPENINFO = "ORACLE_XA:Oracle_XA+Acc=P/scott/tiger+SesTm=100+LogDir=.+DbgFl=0x7+MaxCur=15+Threads=true"
TMSNAME = TMS_ORA
TMSCOUNT = 2
For more information about the XA parameter, see the "A Oracle XA" chapter in the Fundamentals section of the Oracle Corporation Oracle8i Application Developer's Guide.
Note: For single-threaded JavaServerXA operation, skip this step.
Listing 7-5 shows an example of JavaServerXA configured for multithreading in a sample UBBCONFIG.
Listing 7-5 Multithreaded Server Configuration in Sample UBBCONFIG
*SERVERS
DEFAULT:
RESTART = Y
MAXGEN = 5
...
JavaServerXA
SRVGRP = BANK_GROUP1
SRVID = 2
SRVTYPE = JAVA
CLOPT = "-A -- -M 10 BankApp.jar TellerFactory_1 bank_pool"
RESTART = N
To specify connection pooling, you need to specify SRVTYPE=JAVA in the SERVERS section.
Listing 7-6 JDBC Connection Pool Settings in Sample UBBCONFIG
*JDBCCONNPOOLS
bank_pool
SRVGRP = BANK_GROUP1
SRVID = 2
DRIVER = "weblogic.jdbc20.oci815.Driver"
URL = "jdbc:weblogic:oracle:beq-local"
PROPS = "user=scott;password=tiger;server=Beq-Local"
ENABLEXA = Y
INITCAPACITY = 2
MAXCAPACITY = 10
CAPACITYINCR = 1
CREATEONSTARTUP = Y
Implementing Distributed Transactions
This topic includes the following sections:
In addition to the fully supported examples supplied on the CD-ROM with this release of WebLogic Enterprise, the BEA WebLogic Enterprise team provides several unsupported code examples on a password protected Web site for WebLogic Enterprise customers. The code samples in this topic come from a version of the WebLogic Enterprise XA Bankapp sample application that is available from the unsupported samples WebLogic Enterprise Web site. The URL for the unsupported samples WebLogic Enterprise Web site is specified in the product Release Notes under "About This BEA WebLogic Enterprise Release" in the subsection "Unsupported Samples and Tools Web Page."
This application is different from the one described in the Bankapp Sample Using XA in the WebLogic Enterprise online documentation.
Note: This topic does not attempt to fully describe this sample application. It merely uses code fragments to illustrate the use of the JDBC/XA driver in a CORBA application.
Importing Packages
Listing 7-7 shows the packages that the application imports. In particular, note that:
Listing 7-7 Importing Required Packages
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import com.beasys.Tobj.*;
Initializing the TransactionCurrent Object Reference
Listing 7-8 shows initializing the TransactionCurrent object reference, which will be used by the Teller operations to start and stop transactions.
Listing 7-8 Initializing the TransactionCurrent Object Reference
static org.omg.CosTransactions.Current trans_cur_ref;
org.omg.CORBA.Object trans_cur_oref = TP.bootstrap().resolve_initial_references("TransactionCurrent");
Finding the Connection Pool via JNDI
Listing 7-9 shows finding the connection pool via JNDI. The connection pool name is registered on the server group and is passed in as a command-line parameter upon server startup. Subsequent database connections are obtained from this pool.
Listing 7-9 Finding the Connection Pool via JNDI
static DataSource pool;
...
public void get_connpool(String pool_name)
throws Exception
{
try {
javax.naming.Context ctx = new InitialContext();
pool = (DataSource)ctx.lookup("jdbc/" + pool_name);
}
catch (javax.naming.NamingException ex){
TP.userlog("Couldn't obtain JDBC connection pool: " + pool_name);
throw ex;
}
}
}
Setting Up XA Distributed Transactions
Listing 7-10 shows setting up XA distributed transactions by calling the open_xa_rm method (in server.initialize) and obtaining a reference to the TransactionCurrent object.
Note: This step is required for CORBA applications but not for EJB or RMI applications.
Listing 7-10 Setting Up XA Distributed Transactions
TP.open_xa_rm();
org.omg.CORBA.Object trans_cur_oref = TP.bootstrap().resolve_initial_references("TransactionCurrent");
trans_cur_ref = org.omg.CosTransactions.CurrentHelper.narrow(trans_cur_oref);
Performing a Distributed Transaction
Listing 7-11 shows a complete distributed transaction that involves the transfer of money from one bank account to another.
Sequence of Tasks
The application performs the distributed application in the following sequence:
Listing 7-11 Performing a Distributed Transaction
public void transfer(int fromAccountID, int toAccountID, float amount, BalanceAmountsHolder balances)
throws AccountRecordNotFound, IOException, InsufficientFunds
{
boolean success = false;
try {
// Increment the number of requests the teller has received.
tellerStats.totalTellerRequests += 1;
// Begin the global transaction.
BankAppServerImpl.trans_cur_ref.begin();
// Flag this as a transfer.
transferInProgress = true;
// Perform the withdrawal first.
float withdrawalBalance = withdraw(fromAccountID, amount);
// Perform the deposit next.
float depositBalance = deposit(toAccountID, amount);
balances.value = new BalanceAmounts();
balances.value.fromAccount = withdrawalBalance;
balances.value.toAccount = depositBalance;
success = true;
// Catch any exceptions thrown during database operations
}
catch (AccountRecordNotFound e) {
throw e;
}
catch (InsufficientFunds e) {
throw e;
}
catch (IOException e) {
throw e;
}
catch(Exception e) {
TP.userlog("Exception caught in transfer(): "
+ e.getMessage());
e.printStackTrace();
throw new org.omg.CORBA.INTERNAL();
}
finally {
try {
// Complete the distributed transaction and
// update the Teller statistics.
if (success) {
tellerStats.totalTellerSuccess += 1;
BankAppServerImpl.trans_cur_ref.commit(true);
} else {
tellerStats.totalTellerFail += 1;
BankAppServerImpl.trans_cur_ref.rollback();
}
}
catch(Exception e) {
TP.userlog("Unexpected Exception thrown during commit or rollback: " + e.getMessage());
e.printStackTrace();
throw new org.omg.CORBA.INTERNAL();
}
transferInProgress = false;
}
}
The withdraw Method
Listing 7-12 shows the withdraw method that is invoked in Listing 7-11. The withdraw method shows accessing the database to withdraw money from the specified account.
Listing 7-12 withdraw method
public float withdraw(int accountID, float amount)
throws AccountRecordNotFound,
IOException,
InsufficientFunds,
TellerInsufficientFunds
{
boolean success = false;
try {
if (!transferInProgress) {
// This is just a plain withdrawal; it is NOT a transfer.
// Increment the number of requests that this teller
// has received.
tellerStats.totalTellerRequests += 1;
// Decrement the balance left in the Teller's ATM machine.
tellerStats.totalTellerBalance -= amount;
// Begin the global transaction.
BankAppServerImpl.trans_cur_ref.begin();
// Check to see if the minimum TELLER threshold balance
// has not been reached; if so, amount will be added back in
// in the finally clause.
if (tellerStats.totalTellerBalance < MinTellerBalance)
throw new TellerInsufficientFunds();
}
AccountDataHolder accountDataHolder =
new AccountDataHolder(new AccountData());
accountDataHolder.value.accountID = accountID;
accountDataHolder.value.balance = -amount;
// Withdraw the money from the account.
theDBAccess_ref.update_account(accountDataHolder);
success = true;
return(accountDataHolder.value.balance);
}
catch (AccountRecordNotFound e) {
throw e;
}
catch (InsufficientFunds e) {
throw e;
}
catch (TellerInsufficientFunds e) {
throw e;
}
catch (DataBaseException e) {
throw new IOException();
}
catch(Exception e) {
TP.userlog("Exception caught in withdraw(): "
+ e.getMessage());
e.printStackTrace();
throw new org.omg.CORBA.INTERNAL();
}
finally {
// Terminate the transaction and update the Teller statistics.
if (!transferInProgress) {
try {
if (success) {
tellerStats.totalTellerSuccess += 1;
BankAppServerImpl.trans_cur_ref.commit(true);
} else {
tellerStats.totalTellerFail += 1;
tellerStats.totalTellerBalance += amount;
BankAppServerImpl.trans_cur_ref.rollback();
}
}
catch(Exception e) {
TP.userlog("Unexpected Exception thrown during commit or rollback: " + e.getMessage());
e.printStackTrace();
throw new org.omg.CORBA.INTERNAL();
}
}
}
}
The deposit Method
Listing 7-13 shows the deposit method that is invoked in Listing 7-11. The deposit method shows accessing the database deposit money to the specified account.
Listing 7-13 deposit method
|
Copyright © 2000 BEA Systems, Inc. All rights reserved.
|