Skip Headers

Oracle9iAS Containers for J2EE Services Guide
Release 2 (9.0.2)

Part Number A95879-01
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

10
Java Transaction API

This chapter describes the Oracle9iAS Containers for J2EE (OC4J) Transaction API.

This chapter covers the following topics:

Introduction

Enterprise JavaBeans use Java Transaction API (JTA) 1.0.1 for managing transactions. This chapter discusses the method for using JTA in OC4J. It does not cover JTA concepts--you must understand how to use and program global transactions before reading this chapter. See the Sun Microsystems Web site for more information. Code examples are available for download from the OC4J sample code site off OTN.

JTA involves enlisting resources and demarcating the transaction.

Enlisting resources: The complexity of your transaction is determined by how many resources your application enlists.

Demarcating transactions: Your application demarcates the transaction through either bean-managed or container-managed transactions.

Single-Phase Commit

Single-phase commit (1pc) is a transaction that involves only a single resource. JTA transactions consist of enlisting resources and demarcating transactions.

Enlisting a Single Resource

To enlist the single resource in the single-phase commit, you must do the following:

  1. Configure the DataSource in data-sources.xml. For single-phase commit, use an emulated data source.

  2. Retrieve a connection to this DataSource in your bean implementation after the transaction has begun.

    1. After the transaction has begun (demarcated), lookup the DataSource from the JNDI name space.

    2. Retrieve a connection off this DataSource object using the getConnection method.

Configuring the DataSource

Use an emulated data source for a single phase commit. Refer to the Chapter 15, "Data Sources" for information on emulated and non-emulated data source types.

Use the default DataSource object if you can for the single-phase commit JTA transaction. After modifying this data source url attribute with your database URL information, retrieve the data source in your code using a JNDI lookup with the JNDI name configured in the ejb-location attribute. Configure a DataSource for each database involved in the transaction.

<data-source
  class="com.evermind.sql.DriverManagerDataSource"
  name="OracleDS"
  location="jdbc/OracleCoreDS"
  xa-location="jdbc/xa/OracleXADS"
  ejb-location="jdbc/OracleDS"
  connection-driver="oracle.jdbc.driver.OracleDriver"
  username="scott"
  password="tiger"
  url="jdbc:oracle:thin:@myhost:myport:mySID"
  inactivity-timeout="30"
/>

The following are the expected attribute definitions:

Retrieving the DataSource Connection

Before executing any SQL statements against tables in the database, you must retrieve a connection to that database. For these updates to be included in the JTA transaction, you must do one of the following:

  1. After the transaction has begun (demarcated), lookup the DataSource from the JNDI name space. You can use one of two methods for the retrieval.

  2. Retrieve a connection off this DataSource object using the getConnection method.

There are two methods for retrieving the DataSource out of the JNDI namespace, as follows:

Perform JNDI Lookup on DataSource Definition

You can perform a lookup on the JNDI name bound to the DataSource definition in the data-sources.xml file and retrieve a connection, as follows:

Context ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup("jdbc/OracleDS");
Connection conn = ds.getConnection();
Perform JNDI Lookup Using Environment

You can perform a lookup on a logical name defined in the environment of the bean container. For more information, see the "Data Sources" chapter. Basically, define the logical name in the J2EE deployment descriptor as follows:

<resource-ref>
     <res-ref-name>jdbc/OracleMappedDS</res-ref-name>
     <res-type>javax.sql.DataSource</res-type>
     <res-auth>Container</res-auth>
</resource-ref>

Map the <res-ref-name> in the OC4J-specific deployment descriptor to the JNDI name bound in the data-sources.xml file as follows:

<resource-ref-mapping name="jdbc/OracleMappedDS" location="jdbc/OracleDS" />

where "jdbc/OracleDS" is the JNDI name defined in the data-sources.xml file.

Then retrieve the data source using the environment JNDI lookup and create a connection, as shown below:

InitialContext ic = new InitialContext();
DataSource ds = ic.lookup("java:comp/env/jdbc/OracleMappedDS");
Connection conn = ds.getConnection();

Example 10-1 Retrieving A Connection Using Portable JNDI Lookup

If you are using JDBC, you can start preparing and executing statements against the database. If you are using SQLJ, create a default context to specify in the #sql statement.

The following shows a small portion of an employee session bean that uses container-managed transactions and uses SQLJ for updating the database.

int empno = 0;
double salary = 0.0;
DataSource remoteDS;
Context ic;

//Retrieve the initial context. No JNDI properties are necessary here
ic = new InitialContext ();

//Lookup the DataSource using the <resource-ref> definition
remoteDS = (DataSource)ic.lookup ("java:comp/env/jdbc/OracleMappedDS");

//Retrieve a connection to the database represented by this DataSource
Connection remoteConn = remoteDS.getConnection ("SCOTT", "TIGER");

//Since this implementation uses SQLJ, create a default context for this 
//connection.
DefaultContext dc = new DefaultContext (remoteConn);

//Perform the SQL statement against the database, specifying the default 
//context for the database in brackets after the #sql statement.
#sql [dc] { select empno, sal  from emp where ename = :name  };

Demarcating the Transaction

With JTA, you can demarcate the transaction yourself by specifying that the bean is bean-managed transactional, or designate that the container should demarcate the transaction by specifying that the bean is container-managed transactional. Container-managed transaction is available only to entity beans and stateful beans.


Note:

Currently, the client cannot demarcate the transaction. Propagation of the transaction context cannot cross OC4J instances. Thus, neither a remote client nor a remote EJB can initiate or join the transaction.


You specify the type of demarcation in the bean deployment descriptor. The following shows a session bean that is declared as container-managed transactional by defining the <transaction-type> element as "Container". To configure the bean to use bean-managed transactional demarcation, define this element to be "Bean".

<session>
  <description>no description</description>
  <ejb-name>myEmployee</ejb-name>
  <home>cmtxn.ejb.EmployeeHome</home>
  <remote>cmtxn.ejb.Employee</remote>
  <ejb-class>cmtxn.ejb.EmployeeBean</ejb-class>
  <session-type>Stateful</session-type>
  <transaction-type>Container</transaction-type>
  <resource-ref>
   <res-ref-name>jdbc/OracleMappedDS</res-ref-name>
   <res-type>javax.sql.DataSource</res-type>
   <res-auth>Application</res-auth>
  </resource-ref>
</session>

Container-Managed Transactional Demarcation

If you define your bean to use container-managed transactions (CMT), then you must specify how the container manages the JTA transaction for this bean in the <trans-attribute> element in the deployment descriptor. The following table briefly describes the transaction attribute types that you should specify in the deployment descriptor:

Table 10-1 Transaction Attributes

Transaction Attribute Description

NotSupported

The bean is not involved in a transaction. If the bean invoker calls the bean while involved in a transaction, the invoker's transaction is suspended, the bean executes, and when the bean returns, the invoker's transaction is resumed.

Required

The bean must be involved in a transaction. If the invoker is involved in a transaction, the bean uses the invoker's transaction. If the invoker is not involved in a transaction, the container starts a new transaction for the bean.

Supports

Whatever transactional state that the invoker is involved in is used for the bean. If the invoker has begun a transaction, the invoker's transaction context is used by the bean. If the invoker is not involved in a transaction, neither is the bean.

RequiresNew

Whether or not the invoker is involved in a transaction, this bean starts a new transaction that exists only for itself. If the invoker calls while involved in a transaction, the invoker's transaction is suspended until the bean completes.

Mandatory

The invoker must be involved in a transaction before invoking this bean. The bean uses the invoker's transaction context.

Never

The bean is not involved in a transaction. Furthermore, the invoker cannot be involved in a transaction when calling the bean. If the invoker is involved in a transaction, a RemoteException is thrown.

The following <container-transaction> portion of the deployment descriptor demonstrates how this bean specifies the RequiresNew transaction attribute for all (*) methods of the myEmployee EJB.

<assembly-descriptor>
...
<container-transaction>
     <description>no description</description>
     <method>
        <ejb-name>myEmployee</ejb-name>
        <method-name>*</method-name>
     </method>
     <trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
</assembly-descriptor>

No bean implementation is necessary to start, commit, or rollback the transaction. The container handles all of these functions based on the transaction attribute specified in the deployment descriptor.

Bean-Managed Transactions

If you declare the bean as bean-managed transactional (BMT) within the <transaction-type>, then the bean implementation must demarcate the start, commit, or rollback for the global transaction. In addition, you must be careful to retrieve the DataSource connection after you start the transaction and not before.

Programmatic transaction demarcation

For programmatic transaction demarcation, the bean writer can use either JTA's user transaction interface or JDBC's connection interface methods. The bean writer must explicitly start and commit or rollback transactions within the timeout interval.

Programmatic transaction demarcation must be used by Web components (JSP, Servlets) and Stateless Session beans; Stateful Session beans may use it; entity beans must use declarative transaction demarcation.

Client-side transaction demarcation

This form of transaction demarcation is not required by the J2EE specification, and is not recommended for performance and latency reasons. OC4J does not support client-side transaction demarcation.

JTA Transactions

The Web component or bean writer must explicitly issue begin, commit and rollback methods of the UserTransaction interface as follows:

Context initCtx = new Initial Context(); 
ut = (UserTransaction)  initCtx.lookup("java:comp/env/UserTransaction"); 
... 
ut.begin(); 
// Commit the transaction started in ejbCreate. 
Try { 
        ut.commit(); 
} catch (Exception ex) { .....} 

JDBC Transactions

The javax.sql.Connection class provides commit and rollback methods. JDBC transactions implicitly begin with the first SQL statement that follows the most recent commit, rollback, or connect statement.

The following code example, which is available for download from the OC4J sample code OTN siteassumes that there are no errors.

This example demonstrates the combination of demarcating a transaction and enlisting the database resources in the following manner:

  1. Retrieves the UserTransaction object from the bean context.

  2. Starts the transaction with the begin method.

  3. Enlists the database as "Retrieving the DataSource Connection" section describes.

This example is the same as listed in the "Retrieving the DataSource Connection" section, but it is surrounded by UserTransaction begin and commit methods.

DataSource remoteDS;
Context ic;
int empno = 0;
double salary = 0.0;

//Retrieve the UserTransaction object. Its methods are used for txn demarcation
UserTransaction ut = ctx.getUserTransaction ();

//Start the transaction
ut.begin();

//Retrieve the initial context. No JNDI properties are necessary here
	ic = new InitialContext ();

//Lookup the OrionCMTDataSource that was specified in the data-sources.xml 
remoteDS = (DataSource)ic.lookup ("java:comp/env/jdbc/OracleCMTDS");

//Retrieve a connection to the database represented by this DataSource
Connection remoteConn = remoteDS.getConnection ("SCOTT", "TIGER");

//Since this implementation uses SQLJ, create a default context for this 
//connection.
DefaultContext dc = new DefaultContext (remoteConn);

//Perform the SQL statement against the database, specifying the default 
//context for the database in brackets after the #sql statement.
#sql [dc] { select empno, sal  from emp where ename = :name  };

//Assuming everything went well, commit the transaction.
ut.commit();

Two-Phase Commit

The main focus of JTA is to declaratively or programmatically start and end simple and global transactions. When a global transaction is completed, all changes are either committed or rolled back. The difficulty in implementing a two-phase commit transaction is in the configuration details. To understand this section, you must understand non-emulated data sources. See the non-emulated data source section in the "Data Sources" chapter.

Figure 10-1 shows an example of a two-phase commit engine--jdbc/OracleCommitDS--coordinating two databases in the global transaction--jdbc/OracleDS1 and jdbc/OracleDS2. Refer to this example when going through the steps for configuring your JTA two-phase commit environment.

Figure 10-1 Two-Phase Commit Example

Text description of jtaa.gif follows

Text description of the illustration jtaa.gif

Configuring Two-Phase Commit Engine

When a global transaction involves multiple databases, the changes to these resources must all be committed or rolled back at the same time. That is, when the transaction ends, the transaction manager contacts a coordinator--also known as a two-phase commit engine--to either commit or roll back all changes to all included databases. The two-phase commit engine is an Oracle9i database that is configured with the following:

To facilitate this coordination, you must configure the following:

  1. Designate and configure an Oracle9i database as the two-phase commit engine. When you have defined the database that is to act as the two-phase commit engine, configure it as follows:

    1. Define a non-emulated data source, using OrionCMTDataSource, for the two-phase commit engine database in the data-sources.xml file. The following code defines the two-phase commit engine OrionCMTDataSource in the data-sources.xml file.

      <data-source
        class="com.evermind.sql.OrionCMTDataSource"
        name="OracleCommitDS"
        location="jdbc/OracleCommitDS"
        connection-driver="oracle.jdbc.driver.OracleDriver"
        username="coordusr"
        password="coordpwd"
        url="jdbc:oracle:thin:@mysun:5521:jis"
        inactivity-timeout="30"
      />
      
      
    2. Refer to the two-phase commit engine DataSource in either the global or local orion-application.xml file. The global XML file exists in the config/ directory. The local XML file exists in the application EAR file.

      Configure the two-phase commit engine in the orion-application.xml as follows:

      <commit-coordinator>
       <commit-class class="com.evermind.server.OracleTwoPhaseCommitDriver" />
       <property name="datasource" value="jdbc/OracleCommitDS" />
       <property name="username" value="coordusr" />
       <property name="password" value="coordpwd" />
      </commit-coordinator>
      
      
      

      The parameters are as follows:

      The following example defines the two-phase commit engine in the <commit-coordinator> element in the application.xml file.

      • The OracleTwoPhaseCommitDriver class is defined in the <commit-class> element.

      • The JNDI name for the OrionCMTDataSource is identified in the <property> element whose name is "datasource".

      • The username is identified in the <property> element whose name is "username".

      • The password is identified in the <property> element whose name is "password".

  2. Create the user on the two-phase commit engine that facilitates the transaction. First, the user opens a session from the two-phase commit engine to each of the involved databases. Second, it must be granted the CONNECT, RESOURCE, CREATE SESSION privileges to be able to connect to each of these databases. The FORCE ANY TRANSACTION privilege allows the user to commit or roll back the transaction.

    Additionally, create this user and grant these permissions on all databases involved in the transaction.

    For example, if the user that is needed for completing the transaction is COORDUSR, you would do the following on the two-phase commit engine and EACH database involved in the transaction:

    CONNECT SYSTEM/MANAGER;
    CREATE USER COORDUSR IDENTIFIED BY COORDUSR;
    GRANT CONNECT, RESOURCE, CREATE SESSION TO COORDUSR;
    GRANT FORCE ANY TRANSACTION TO COORDUSR;
    
    
  3. Configure fully-qualified public database links (using the CREATE PUBLIC DATABASE LINK command) from the two-phase commit engine to each database that may be involved in the global transaction. This is necessary for the two-phase commit engine to communicate with each database at the end of the transaction. The COORDUSR must be able to connect to all participating databases using these links.

    This example has two databases involved in the transaction. The database link from the two-phase commit engine to each database is provided on each OrionCMTDataSource definition in a <property> element in the data-sources.xml file. See the next step for the "dblink" <property> element.

  4. Configure non-emulated data source objects of type OrionCMTDataSource for each database involved in the transaction with the following information:

    1. The JNDI bound name for the object.

    2. The URL for creating a connection to the database.

    3. The fully-qualified database link from the two-phase commit engine to this database. This is provided in a <property> element within the DataSource definition in the data-sources.xml file.

    The following OrionCMTDataSource objects specify the two databases involved in the global transaction. Notice that each of them has a <property> element with the name "dblink" that denotes the database link from the two-phase commit engine to itself.

    <data-source
      class="com.evermind.sql.OrionCMTDataSource"
      name="OracleCMTDS1"
      location="jdbc/OracleDS1"
      connection-driver="oracle.jdbc.driver.OracleDriver"
      username="scott"
      password="driver"
      url="jdbc:oracle:thin:@mysun:5521:jis"
      inactivity-timeout="30"
      <property name="dblink"
       value="LINK.REGRESS.RDBMS.DEV.US.ORACLE.COM"/>
    </data-source>
    
    <data-source
      class="com.evermind.sql.OrionCMTDataSource"
      name="OracleCMTDS2"
      location="jdbc/OracleDS2"
      connection-driver="oracle.jdbc.driver.OracleDriver"
      username="scott"
      password="driver"
      url="jdbc:oracle:thin:@mysun:6521:jis"
      inactivity-timeout="30"
      <property name="dblink"
       value="LINK.REGRESS.RDBMS.DEV.US.ORACLE.COM"/>
    </data-source>
    
    


    Note:

    If you change the two-phase commit engine, you must update all database links--both within the new two-phase commit engine as well as within the OrionCMTDataSource <property> definitions.


Once the two-phase commit engine and all the databases involved in the transaction are configured, you can start and stop a transaction in the same manner as the single-phase commit. See "Single-Phase Commit" for more information.

Two-Phase Commit DTD Elements

The following code example contains the elements in the orion-application.xml file that are relevant to the two-phase commit engine:

<!ELEMENT orion-application
(ejb-module*,web-module*,client-module*,security-role-mapping*,
persistence?, library*, principals?, mail-session*, user-manager?,
log?, data-sources?, commit-coordinator?, namespace-access?)>

<!-- Transaction co-ordinator for the server. -->
<!ELEMENT commit-coordinator (commit-class, property*)>

<!ELEMENT commit-class (#PCDATA)>
<!ATTLIST class name CDATA #IMPLIED>

<!-- A property to set when using a custom/3rd-party DataSource. -->
<!ELEMENT property (#PCDATA)>
<!ATTLIST property name CDATA #IMPLIED
value CDATA #IMPLIED
>


Go to previous page Go to next page
Oracle
Copyright © 2002 Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index