Oracle9i CORBA Developer's Guide and Reference
Release 1 (9.0.1)

Part Number A90187-01
Go To Documentation Library
Home
Go To Product List
Book List
Go To Table Of Contents
Contents
Go To Index
Index

Master Index

Feedback

Go to previous page Go to next page

7
Transaction Handling

This chapter covers transaction management for CORBA applications. The CORBA developer can choose to use one of the following transactional APIs provided:

In Oracle9i, Java Transaction API (JTA) 1.0.1 for managing transactions. This chapter assumes that you have a working knowledge of JTA. The discussion focuses mostly on examples and explaining the differences between the Sun Microsystems JTA specification and the Oracle JTA implementation. See http://www.javasoft.com for the Sun Microsystems JTA specification.

Transaction Overview

Transactions manage changes to multiple databases within a single application as a unit of work. That is, if you have an application that manages data within one or more databases, you can ensure that all changes in all databases are committed at the same time if they are managed within a transaction.

Transactions are described in terms of ACID properties, which are as follows:

The JTA implementation, specified by Sun Microsystems, relies heavily on the JDBC 2.0 specification and XA architecture. The result is a complex requirement on applications in order to ensure that the transaction is managed completely across all databases. Sun Microsystems's specifies Java Transaction API (JTA) 1.0.1 and JDBC 2.0 on http://www.javasoft.com.

You should be aware of the following when using JTA within the Oracle9i environment:

Global and Local Transactions

Whenever your application connected to a database using JDBC or a SQL server, you were creating a transaction. However, the transaction involved only the single database and all updates made to the database were committed at the end of these changes. This is referred to as a local transaction.

A global transaction involves a complicated set of management objects--objects that track all of the objects and databases involved in the transaction. These global transaction objects--TransactionManager and Transaction--track all objects and resources involved in the global transaction. At the end of the transaction, the TransactionManager and Transaction objects ensure that all database changes are atomically committed at the same time.

Within a global transaction, you cannot execute a local transaction. If you try, the following error will be thrown:

ORA-2089 "COMMIT is not allowed in a subordinate session."

Some SQL commands implicitly execute a local transaction. All SQL DDL statements, such as "CREATE TABLE", implicitly starts and commits a local transaction under the covers. If you are involved in a global transaction that has enlisted the database that the DDL statement is executing against, the global transaction will fail.

Demarcating Transactions

A transaction is said to be demarcated, which means that each transaction has a definite start and stop point. For example, in a client-side demarcated transaction, the client starts the transaction with a begin method and completes the transaction with either executing the commit or rollback method.

The originating client or object that starts the transaction must also end the transaction with a commit or rollback. If the client begins the transaction, calls out to a server object, the client must end the transaction after the invoked method returns. The invoked server object cannot end the transaction.

In a distributed object application, transactions are demarcated differently if the originator is the client or the server. Where the transaction originates defines the transaction as client-side demarcated or server-side demarcated.

UserTransaction Interface

The following are the methods that you can use for transaction demarcation. These methods are defined within the javax.transaction.UserTransaction interface:

public abstract void begin() throws NotSupported, SystemException;

public abstract void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException;

public abstract void rollback() throws IllegalStateException, SecurityException, SystemException;

public abstract int getStatus() throws SystemException;

public abstract void setRollbackOnly() throws IllegalStateException, SystemException;

public abstract setTransactionTimeout(int seconds) throws SystemException;

Transaction Context Propagation

When you begin a transaction within either a client or a server instance, JTA denotes the originator in the transaction manager. As the transaction involves more objects and resources, the transaction manager tracks all of these objects and resources in the transaction and manages the transaction for these entities.

When an object calls another object, in order for the invoked object to be included in the transaction, JTA propagates the transaction context to the invoked object. Propagation of the transaction context is necessary for including the invoked object into the global transaction.

As shown in Figure 7-1, if the client begins a global transaction, calls a server object in the database, the transaction context is propagated to the server object. If this server object invokes another server object, within the same or a remote database, the transaction context is propagated to this object as well. This ensures that all objects that are supposed to be involved in the global transaction are tracked by the transaction manager.

Figure 7-1 Connection to an Object over IIOP


Text description of transa.gif follows
Text description of the illustration transa.gif

Enlisting Resources

While there are several methods for retrieving a JDBC connection to a database, only one of these methods causes the database to be included in a JTA transaction. The following table lists the normal methods for retrieving JDBC connections:

Table 7-1 JDBC Methods
Retrieval Method  Description 

OracleDriver().
defaultConnection()
 

Pre-JDBC 2.0 method for retrieving the local connection. Use only within local transactions. 

DriverManager.getConnection
("jdbc:oracle:kprb:")
 

Pre-JDBC 2.0 method for retrieving the local connection. Use only within local transactions. 

DataSource.getConnection
("jdbc:oracle:kprb:")
 

JDBC 2.0 method for retrieving connections to the local databases. Can be used for JTA transactions. 

Of these methods, only the DataSource object can be used to include a database resource in the global transaction. In order to ensure that the statements are included within a global transaction, you must do the following:

  1. Bind a JTA DataSource object (OracleJTADataSource) in the JNDI namespace. There are several types of DataSource objects that you can bind. You must bind the JTA type in order for this database to be included in the global transaction.

  2. The object method must retrieve the DataSource object from the JNDI namespace after the global transaction has started.

  3. Retrieve the connection object from this DataSource object using the getConnection method.

An example is shown in "Enlisting Resources on the Server-side".

If your transaction involves more than one database, you must specify an Oracle9i database as the two-phase commit engine. See "Configuring Two-Phase Commit Engine" for more information.

Two-Phase Commit

One of the primary advantages for a global transaction is the number of objects and database resources managed as a single unit within the transaction. If your global transaction involves more than one database resource, you must specify a two-phase commit engine, which is an Oracle9i database designated to manage the changes to all databases within the transaction. The two-phase commit engine is responsible for ensuring that when the transaction ends, all changes to all databases are either totally committed or fully rolled back.

On the other hand, if your global transaction has multiple server objects, but only a single database resource, you do not need to specify a two-phase commit engine. The two-phase commit engine is required only to synchronize the changes for multiple databases. If you have only a single database, single-phase commit can be performed by the transaction manager.


Note:

Your two-phase commit engine can be any Oracle9i database. It can be the database where your server object exists, or even a database that is not involved in the transaction at all. See "Configuring Two-Phase Commit Engine" for a full explanation of the two-phase commit engine setup. 


Figure 7-2 shows three databases enlisted in a global transaction and another database that is designated as the two-phase commit engine. When the global transaction ends, the two-phase commit engine ensures that all changes made to the databases A, B, and the local are committed or rolled back simultaneously.

Figure 7-2 Two-Phase Commit for Global Transactions


Text description of jta_2pc.gif follows
Text description of the illustration jta_2pc.gif

JTA Summary

The following sections summarize the details for demarcating the transaction and enlisting the database in the transaction. These details are explained and demonstrated in the rest of the chapter. However, these tables provide a reference point for you.

Environment Initialization

Before you can retrieve the UserTransaction or DataSource bound objects from the JNDI namespace, you must provide the following before the JNDI lookup:

Methods for Enlisting Database Resources

The DataSource object is used to explicitly enlist the database in the JTA transaction. In order for the database to be correctly enlisted, the DataSource must be bound correctly, and the retrieval mechanism can be one of three methods. These are discussed below:

Table 7-3 JDBC 2.0 DataSource Overview 
  JDBC 2.0 DataSource 

Binding  

You must bind a JTA DataSource into the namespace with the bindds command. The bindds command must contain the -dstype jta option. 

Retrieving DataSource object from remote JNDI provider 

  1. Provide the environment Hashtable, which contains authentication information and namespace URL.

  2. Retrieve the DataSource object through a JNDI lookup that contains the "jdbc_access://" prefix.

 

Retrieving DataSource object from local JNDI provider 

Retrieve the DataSource object using in-session activation. Environment setup and "jdbc_access://" prefix is not required. 

Summary of Single-Phase and Two-Phase Commit

Table 7-4 summarizes the single-phase commit scenario. It covers the JNDI binding requirements and the application implementation runtime requirements.

Table 7-4 Single-Phase Commit
Aspect  Description 

Binding  

  • No binding required for UserTransaction. The UserTransaction object is created for you.

  • If using a DataSource object in the transaction, bind it using the bindds command.

 

Runtime 

  • Retrieve the UserTransaction through a JNDI lookup with the "java:comp/
    UserTransaction
    " string, or a normal JNDI lookup.

  • Your runtime is responsible for starting and terminating the transaction.

  • If using the DataSource object to manage SQL DML statements within the transaction, retrieve the DataSource.

 

Table 7-5 summarizes the two-phase commit scenario.

Table 7-5 Two-Phase Commit Requirements  
Aspect  Requirements 

Binding UserTransaction

One of two scenarios: 

Scenario one is where you bind the UserTransaction WITH a username and password that is to be used to complete all global transactions started from this UserTransaction.

  • You bind a UserTransaction object with the fully-qualified database address of the two-phase commit engine and its username and password.

  • You bind DataSource objects for each database involved in the transaction with a fully-qualified public database link from the two-phase commit engine to itself.

 

Scenario two is where you bind the UserTransaction WITHOUT a username and password. Thus, the username that is used when retrieving the UserTransaction is the user that completes the transaction.

  • You bind a UserTransaction object with the fully-qualified database address of the two-phase commit engine.

  • You bind DataSource objects for each database involved in the transaction with a fully-qualified public database link from the two-phase commit engine to itself.

 

Binding DataSource 

You must bind a JTA DataSource for each database involved in the transaction. You must create public database links, as discussed in the System Administration section. 

System Administration 

  • The user that completes the transaction (as described in the binding section) must have the privilege to commit the transaction on all included databases. There are one of two methods for ensuring that the user can complete the transaction.

    - If the username is not bound with the UserTransaction object, the user that retrieves the UserTransaction both starts and stops the transaction. Thus, this user must be created on all involved database in order to be able to open a session to all databases.

    - If the username is bound with the UserTransaction object is different than the user that retrieves the UserTransaction object, the username bound with the UserTransaction object must be given explicit privilege to complete a transaction it did not start. Thus, make sure that this user exists on each database in order to open sessions to all databases and grant it the "CONNECT, REMOVE, CREATE SESSION, and FORCE ANY TRANSACTION" privileges on each database.

  • Create public database links from the two-phase commit engine to each database involved.

 

Runtime 

Runtime requirements are the same as indicated in the single-phase commit table. 

JTA Server-Side Demarcation

To retrieve any objects or database resources, you can perform in-session activation or remote lookup.

Example 7-1 Server-Side Demarcation for Single-Phase Commit

The following example demonstrates a server object performing an in-session lookup of the UserTransaction and DataSource objects. This example uses a single phase commit transaction. Notice that because this is an in-session activation, none of the following are needed: authentication information, location of the namespace, and the "jdbc_access://" prefix.


Note:

To modify this for two-phase commit, supply a username and password within the environment passed into the initial context constructor.  


ic = new InitialContext ( );

// lookup the usertransaction
UserTransaction ut = (UserTransaction)ic.lookup ("/test/myUT");
...
ut.begin ();

// Retrieve the DataSource 
DataSource ds = (DataSource)ic.lookup ("/test/empDB");

// Get connection to the database through DataSource.getConnection
Connection conn = ds.getConnection ();

JTA Client-Side Demarcation

For JTA, client-side demarcated transactions are programmatically demarcated through the UserTransaction interface (see "UserTransaction Interface"). A UserTransaction object must be bound with the bindut command into the namespace (see "Bind UserTransaction Object in the Namespace"). With client-side transaction demarcation, the client controls the transaction. The client starts a global transaction by invoking the UserTransaction begin method; it ends the transaction by invoking either the commit or rollback methods. In addition, the client must always set up an environment including a Hashtable with authentication information and namespace location URL.

Figure 7-3 shows a client invoking a server object. The client starts a global transaction, then invokes the object. The transactional context is propagated to include the server object.

Figure 7-3 Client Demarcated Global Transaction


Text description of jta_cli_.gif follows
Text description of the illustration jta_cli_.gif

The following must occur for the client to demarcate the transaction:

  1. Initialize a Hashtable environment with the namespace address and authentication information.

  2. Retrieve the UserTransaction object from the namespace within the client logic. When you retrieve the UserTransaction object from any client, the URL must consist of "jdbc_access://" prefix before the JNDI name.

  3. Start the global transaction within the client using UserTransaction.begin().

  4. Retrieve the server object.

  5. Invoke any object methods to be included in the transaction.

  6. End the transaction through UserTransaction.commit() or UserTransaction.rollback().

Example 7-2 shows a client that invokes a server object within the transaction.

Example 7-2 Bind UserTransaction Object in Namespace

Before starting the client, you must first bind the UserTransaction object in the namespace. To bind a UserTransaction object to the name "/test/myUT" in the namespace located on nsHost, execute the following:

sess_sh -service jdbc:oracle:thin:@nsHost:5521:ORCL -user SCOTT -password TIGER
& bindut /test/myUT

See "Bind UserTransaction Object in the Namespace" for more information.

Developing the Client Application

After binding the UserTransaction object, your client code can retrieve the UserTransaction object and start a global transaction. Since the client is retrieving the UserTransaction object from a remote site, the lookup requires authentication information, location of the namespace, and the "jdbc_access://" prefix.

EmployeeInfo info;
String sessiiopURL = args [0];
String objectName = args [1];

//Set up the service URL to where the UserTransaction object 
//is bound. Since from the client, the connection to the database
//where the namespace is located can be communicated with over either 
//a Thin or OCI JDBC driver. This example uses a Thin JDBC driver.
String namespaceURL = "jdbc:oracle:thin:@nsHost:1521:ORCL";

// lookup usertransaction object in the namespace
//1.(a) Authenticate to the database.
// create InitialContext and initialize for authenticating client
Hashtable env = new Hashtable ();
env.put (Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
env.put (Context.SECURITY_PRINCIPAL, "SCOTT");
env.put (Context.SECURITY_CREDENTIALS, "TIGER");
env.put (Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);
//1.(b) Specify the location of the namespace where the transaction objects
//   are bound.
env.put(jdbc_accessURLContextFactory.CONNECTION_URL_PROP, namespaceURL);
Context ic = new InitialContext (env);

//2. Retrieve the UserTransaction object from JNDI namespace
UserTransaction  ut = (UserTransaction)ic.lookup ("jdbc_access://test/myUT");

//3. Start the transaction
ut.begin();

//4. Retrieve the server object reference 
// lookup employee object in the namespace
Employee employee = (Employee)ic.lookup
("sess_iiop://myhost:1521:orcl/test/employee"); //5. Perform business logic. ... //6. End the transaction //Commit the updated value ut.commit ();

JTA Client-Side Demarcation Including Databases

The previous example showed how a transaction context was propagated to server objects from a client within the JTA global transaction. When you execute the server object, the transaction is propagated over the IIOP transport layer. In addition to invoking IIOP server objects, you may wish to update databases over JDBC connections. This section shows how you enlist databases using a JDBC connection in tandem with the IIOP server object propagation.

Figure 7-4 demonstrates how the client can open both an IIOP and a JDBC connection to the database. To open the JDBC connection within the context of a global transaction, you must use a JTA DataSource object.

Figure 7-4 Client Creating Both JDBC and IIOP Connections


Text description of jta_two.gif follows
Text description of the illustration jta_two.gif

To include a remote database within the transaction from a client, you must use a DataSource object, which has been bound in the namespace as a JTA DataSource. Then, invoke the getConnection method of the DataSource object after the transaction has started, and the database is included in the global transaction. See "Enlisting Resources" for more information.

The following must occur in the client runtime to demarcate the transaction:

  1. Initialize a Hashtable environment with the namespace address and authentication information.

  2. Retrieve the UserTransaction object from the namespace within the client logic. When you retrieve the UserTransaction object from the client, the URL must consist of "jdbc_access://" prefix before the JNDI name.

  3. Start the global transaction within the client using UserTransaction.begin().

  4. Enlist any database resources to be included in the transaction by opening a connection to the specified database, as follows:

    1. Retrieve the DataSource object from the namespace within the client logic. When you retrieve the DataSource object from any client, the URL must consist of "jdbc_access://" prefix before the JNDI name.

    2. Open a connection to the database through DataSource.getConnection method.

  5. Retrieve the object reference.

  6. Invoke any object methods to be included in the transaction.

  7. Invoke SQL DML statements against any enlisted databases. SQL DDL creates a local transaction that will abort the global transaction. Thus, SQL DDL cannot be executed within a JTA transaction.

  8. End the transaction through UserTransaction.commit() or UserTransaction.rollback().

Example 7-3 shows a client that invokes a server object and enlists a single database within the transaction.

Example 7-3 Employee Client Code for Client Demarcated Transaction

Before starting the client, you must first bind the UserTransaction and DataSource objects in the JNDI namespace. See "Bind UserTransaction Object in the Namespace" and "Bind DataSource Object in the Namespace" for directions on the binding these objects.

sess_sh -service jdbc:oracle:thin:@nsHost:5521:ORCL -user SCOTT -password TIGER
> bindut /test/myUT
> bindds /test/DataSource/empDB -url jdbc:oracle:thin:@empHost:5521:ORCL 
-dstype jta

Developing the Client Application

The following example follows the steps listed in "JTA Client-Side Demarcation Including Databases".

//Set up the service URL to where the UserTransaction object 
//is bound. Since from the client, the connection to the database
//where the namespace is located can be communicated with over either 
//a Thin or OCI JDBC driver. This example uses a Thin JDBC driver.
String namespaceURL = "jdbc:oracle:thin:@nsHost:1521:ORCL";

// lookup usertransaction object in the namespace
//1.(a) Authenticate to the database.
// create InitialContext and initialize for authenticating client
Hashtable env = new Hashtable ();
env.put (Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
env.put (Context.SECURITY_PRINCIPAL, "SCOTT");
env.put (Context.SECURITY_CREDENTIALS, "TIGER");
env.put (Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);
//1.(b) Specify the location of the namespace where the transaction objects
//   are bound.
env.put(jdbc_accessURLContextFactory.CONNECTION_URL_PROP, namespaceURL);
Context ic = new InitialContext (env);

//2. Retrieve the UserTransaction object from JNDI namespace
ut = (UserTransaction)ic.lookup ("jdbc_access://test/myUT");

//3. Start the transaction
ut.begin();

//4.(a) Retrieve the DataSource (that was previously bound with bindds in
// the namespace. After retrieving the DataSource...
// get a connection to a database. You need to provide authentication info
// for a remote database lookup, similar to what you would do from a client.
// In addition, if this was a two-phase commit transaction, you must provide
// the username and password.
DataSource ds = (DataSource)ic.lookup ("jdbc_access://test/empDB");

//4.(b). Get connection to the database through DataSource.getConnection
// in this case, the database requires the same username and password as
// set in the environment.
Connection conn = ds.getConnection ("SCOTT", "TIGER");

//5. Retrieve the server object reference 
// lookup employee object in the namespace
Employee employee = (Employee)ic.lookup (sessiiopURL + objectName);

//6. Perform business logic.
...

//7. Close the database connection.
conn.close ();

//8. End the transaction
//Commit the updated value
ut.commit ();
}

Enlisting Resources on the Server-side

The databases that the object accesses must be enlisted to be included within the global transaction. This is discussed more in "Enlisting Resources" and "Bind DataSource Object in the Namespace".

If you access an Oracle9i database from the server that should be included in the transaction, you must open the connection to the database after the global transaction starts.


Note:

At this time, the Oracle JTA implementation does not support including non-Oracle databases in a global transaction. 


Example 7-4 Enlist Database in Single Phase Transaction

The following example enlists a database in the global transaction.

//retrieve the initial context.
InitialContext ic = new InitialContext ();

// lookup the usertransaction 
UserTransaction ut = (UserTransaction)ic.lookup ("/test/myUT");

//start the transaction
ut.begin ();

// get a connection to the local database. If this was a two-phase commit 
// transaction, you would provide the username and password for the 2pc engine
DataSource ds = (DataSource)ic.lookup (dsName);

// get connection to the local database through DataSource.getConnection
Connection conn = ds.getConnection ("SCOTT", "TIGER");

//perform your SQL against the database.
//prepare and execute a sql statement. retrieve the employee's selected benefits
PreparedStatement ps =
    conn.prepareStatement ("update emp set ename = :(employee.name), 
sal = :(employee.salary) where empno = :(employee.number)"); .... //do work ps.close(); } //close the connection conn.close(); // commit the transaction ut.commit (); //return the employee information. return new EmployeeInfo (name, empno, (float)salary);

Example 7-5 Using SQLJ with Explicit Enlistment

As in Example 7-4, you would retrieve the JTA DataSource from the JNDI provider, retrieve the connection, retrieve a context from that connection, and then provide the context on the SQLJ command-line.

//retrieve the initial context.
InitialContext ic = new InitialContext ();

// lookup the usertransaction 
UserTransaction ut = (UserTransaction)ic.lookup ("/test/myUT");

//start the transaction
ut.begin ();

// get a connection to the local database. If this was a two-phase commit 
// transaction, you would provide the username and password for the 2pc engine
DataSource ds = (DataSource)ic.lookup (dsName);

// get connection to the local database through DataSource.getConnection
Connection conn = ds.getConnection ("SCOTT", "TIGER");

//setup the context for issuing SQLJ against the database
DefaultContext defCtx = new DefaultContext (conn);

//issue SQL DML statements against the database
#sql [defCtx] { update emp set ename = :(remoteEmployee.name), 
	sal = :(remoteEmployee.salary) 
	  where empno = :(remoteEmployee.number) };

//close the connection
conn.close();

// commit the transaction
ut.commit ();

//return the employee information.
return new EmployeeInfo (name, empno, (float)salary);

Binding Transactional Objects in the Namespace

For most global transactions, you will need to bind at least one of the following objects in the namespace:

Bind UserTransaction Object in the Namespace

The bindut command binds a UserTransaction object in the namespace. This object is used for demarcation of global transactions by either a client or by an object.

You must bind a UserTransaction object for both single and two-phase commit transactions through the bindut command of the sess_sh tool.

The options used to bind a UserTransaction object depend on whether the transaction uses a single or two-phase commit, as described below:

Single-Phase Commit Binding for UserTransaction

Single-phase commit requires the JNDI bound name for the UserTransaction object. You do not need to provide the address to a two-phase commit engine. For example, the following binds a UserTransaction with the name of "/test/myUT" that exists for a single-phase commit transaction:

bindut /test/myUT

To bind a UserTransaction object to the name "/test/myUT" in the namespace located on nsHost through the sess_sh command, execute the following:

sess_sh -service jdbc:oracle:thin:@nsHost:5521:ORCL -user SCOTT -password TIGER
& bindut /test/myUT
Two-Phase Commit Binding for UserTransaction

Two-phase commit binding requires the JNDI bound name for the UserTransaction object and the address to a two-phase commit engine. You provide a URL for the two-phase commit engine in the bindut command, which can be either a JDBC URL or a sess_iiop URL.


Note:

The client needs the same information to retrieve the UserTransaction as you give within the bindut command.  


In addition, you can bind a username and password with the UserTransaction object.

The username that is used to commit or rollback the two-phase commit transaction must be created on the two-phase commit engine and on each database involved in the transaction. It needs to be created so that it can open a session from the two-phase commit engine to each of the involved databases using database links. Secondly, it must be granted the CONNECT, RESOURCE, CREATE SESSION privileges to be able to connect to each of these databases. For example, if the user that is needed for completing the transaction is SCOTT, you would do the following on the two-phase commit engine and each database involved in the transaction:

CONNECT SYSTEM/MANAGER;
CREATE USER SCOTT IDENTIFIED BY SCOTT;
GRANT CONNECT, RESOURCE, CREATE SESSION TO SCOTT;

Lastly, if you bound a username and password with the UserTransaction object, it will be using a different username to finalize the transaction than the username used to start the transaction. For this to be allowed, you must grant the FORCE ANY TRANSACTION privileges on each database involved in the transaction in order for two separate users to start and stop the transaction. If SCOTT is the username bound with the UserTransaction object, you would need to do the following in addition to the previous grant:

GRANT FORCE ANY TRANSACTION TO SCOTT;

The following binds a UserTransaction with the name of "/test/myUT" and a two-phase commit engine at "2pcHost" using a JDBC URL:

bindut /test/myUT -url jdbc:oracle:thin:@2pcHost:5521:ORCL

To bind the UserTransaction in the namespace designating the two-phase commit engine at dbsun.mycompany.com with a sess_iiop URL:

bindut /test/myUT -url sess_iiop://dbsun.mycompany.com:2481:ORCL

When the transaction commits, the UserTransaction communicates with the two-phase engine designated in the -url option to commit all changes to all included databases. In this example, the username and password were not bound with the UserTransaction object, so the user that retrieves the UserTransaction object from the JNDI namespace is used to start and stop the transaction. Thus, this user must exist on all involved databases and the two-phase commit engine. The UserTransaction tracks all databases involved in the transaction; the two-phase commit engine uses the database links for these databases to complete the transaction.


Note:

If you change the two-phase commit engine, you must update all database links on all DataSource objects involved in the transaction, and rebind the UserTransaction


Bind DataSource Object in the Namespace

The bindds command binds a DataSource object in the JNDI namespace. In order to enlist any database in a global transaction--including the local database--you must bind a JTA DataSource object to identify each database included in the transaction. There are multiple types of DataSource objects for use with certain scenarios. However, for use with JTA transactions, you must bind a JTA DataSource object, also known as an OracleJTADataSource object, to identify each database included in the transaction. See the bindds command of the sess_sh tool in the Oracle9i Java Tools Reference for a description of other DataSource object types.

Single-Phase Commit Scenario

In a single-phase commit scenario, the transaction only includes a single database in the transaction. Since no coordination for updates to multiple databases is needed, you do not need to specify a coordinator. Instead, you simply provide the JNDI bound name and the URL address information for this database within the OracleJTADataSource object. You do not need to provide a database link for a transaction coordinator.

Use the bindds command of the sess_sh tool to bind an DataSource object in the namespace. The full command is detailed in the Oracle9i Java Tools Reference. For example, the following binds an OracleJTADataSource with the name of "/test/empDS" that exists within a single-phase commit transaction with the bindds command:

bindds /test/empDS -url jdbc:oracle:thin:@empHost:5521:ORCL -dstype jta

After binding the DataSource object in the namespace, the server can enlist the database within a global transaction.

Two-Phase Commit Scenario

If multiple databases are to be included in the global transaction, you will need a two-phase commit engine, which is an Oracle9i database that is configured to be the transaction coordinator. Basically, the two-phase commit engine must have database links to each of the databases involved in the transaction. When the transaction ends, the transaction manager notifies the two-phase commit engine to either coordinate the commit of all changes to all involved databases or coordinate a roll back of these same changes.

In order to facilitate this coordination, you must configure the following:

  1. Your system administrator must create fully-qualified public database links from the two-phase commit engine (Oracle9i database) to each database involved in the transaction. These database link names must be included when binding the OracleJTADataSource object.

  2. Bind a JTA DataSource (OracleJTADataSource) object for each database in the transaction. You must include the following in the bindds command:

    1. The JNDI bound name for the object

    2. The URL for creating a connection to the database

    3. The fully-qualified public database link from the two-phase commit engine to this database

The following example binds the empDS JTA DataSource into the namespace with 2pcToEmp as the database link name created on the two-phase commit engine:

% bindds /test/empDS -url jdbc:oracle:thin:@dbsun:5521:ORCL
-dstype jta -dblink 2pcToEmp.oracle.com

Configuring Two-Phase Commit Engine

When multiple databases are included in a global transaction, 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:

In order to facilitate this coordination, you must configure the following:

  1. Designate an Oracle9i database as the two-phase commit engine.

  2. Configure fully-qualified public database links (using the CREATE 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. These database link names must be included when binding the JTA DataSource (OracleJTADataSource) object.

  3. Bind a JTA DataSource (OracleJTADataSource) object for each database in the transaction. You must include the following in the bindds command:

    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

      Provide the fully-qualified database link name in the -dblink option of bindds for each individual database when binding that database's DataSource into the namespace.

      bindds /test/empDS -url jdbc:oracle:thin:@empHost:5521:ORCL 
      -dstype jta -dblink 2pcToEmp.oracle.com
      
      


      Note:

      In a two-phase commit scenario, the DataSource object is bound, with respect to the two-phase commit engine. If you change the two-phase commit engine, you must update all database links, and rebind all concerned DataSource and UserTransaction objects. 


  4. Create the user on the two-phase commit engine that facilitates the two-phase commit. This user will open sessions to each resource involved in the transaction and complete the transaction. To do this, the user must be created on each database and granted CONNECT, RESOURCE, and CREATE SESSION privileges. If the user that completes the transaction is different from the user that starts the transaction, you also need to grant the FORCE ANY TRANSACTION privilege. These privileges must be granted on all databases included in the transaction.

    The decision on whether the FORCE ANY TRANSACTION privilege is needed is determined by whether you bound a username and password with the UserTransaction object.

    • If you do not bind a username and password with the UserTransaction, the user that retrieved the UserTransaction will be the same user that is used to perform the commit or rollback for the two-phase commit on all involved databases.

    • If you bind a username and password with the UserTransaction, then this is the username that the two-phase commit will be committed or rolled back with on all involved databases. The transaction will be started by the user that retrieves the UserTransaction object.

    Both types of users must be created, so that it can open a session from the two-phase commit engine to each of the involved databases. Secondly, it must be granted the CONNECT, RESOURCE, CREATE SESSION privileges to be able to connect to each of these databases. For example, if the user that is needed for completing the transaction is SCOTT, you would do the following on the two-phase commit engine and each database involved in the transaction:

    CONNECT SYSTEM/MANAGER;
    CREATE USER SCOTT IDENTIFIED BY SCOTT;
    GRANT CONNECT, RESOURCE, CREATE SESSION TO SCOTT;
    
    
    

    Lastly, if you bound a username and password with the UserTransaction object, it will be using a different username to finalize the transaction than the username used to start the transaction. For this to be allowed, you must grant the FORCE ANY TRANSACTION privileges on each database involved in the transaction in order for two separate users to start and stop the transaction.

    The advantage of binding a username with the UserTransaction is that it is treated as a global user is always committing all transactions started with this UserTransaction object. Thus, if you have more than one JTA transactions, you will only have to create one user and grant privileges to that user on all involved databases.

    For example, if SCOTT is the username bound with the UserTransaction object, you would need to do the following in addition to the previous grant:

    GRANT FORCE ANY TRANSACTION TO SCOTT;
    
    
  5. Bind a UserTransaction into the namespace. You must provide the two-phase commit engine's fully-qualified database address. At this point, you should decide (based on the discussion in step 3) on whether to bind it with a username and password. The following assumes a global username is bound with the UserTransaction.

    bindut /test/myUT -url sess_iiop://dbsun.mycompany.com:2481:ORCL 
    -user SCOTT -password TIGER

Example 7-6 Two-Phase Commit Example

The following example shows a server object that performs an in-session activation to retrieve both the UserTransaction and DataSource objects that have been bound locally. The UserTransaction was bound with the two-phase commit engine's URL, username, and password. The DataSource objects were all bound with the proper database links.

//with the environment set, create the initial context.
InitialContext ic = new InitialContext ();
UserTransaction ut = (UserTransaction)ic.lookup ("/test/myUT");

//With the same username and password for the 2pc engine,
// lookup the local datasource and a remote database.
DataSource localDS = (DataSource)ic.lookup ("/test/localDS");

//remote lookup requires environment setup
Hashtable env = new Hashtable ();
env.put (Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
env.put (Context.SECURITY_PRINCIPAL, user);
env.put (Context.SECURITY_CREDENTIALS, password);
env.put (Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);
env.put(jdbc_accessURLContextFactory.CONNECTION_URL_PROP, namespaceURL);
Context ic = new InitialContext (env);
 
//retrieve the DataSource for the remote database
DataSource remoteDS = (DataSource)ic.lookup ("jdbc_access://test/NewYorkDS");

//retrieve connections to both local and remote databases
Connection localConn = localDS.getConnection ();
Connection remoteConn = remoteDS.getConnection ();
...
//close the connections
localConn.close();
remoteConn.close();

//end the transaction
 ut.commit();

Creating DataSource Objects Dynamically

If you want to bind only a single DataSource object in the namespace to be used for multiple database resources, you must do the following:

  1. Bind the DataSource without specifying the URL, host, port, SID, or driver type. Thus, you execute the bindds tool with only the -dstype jta option, as follows:

    sess_sh -service jdbc:oracle:thin:@nsHost:5521:ORCL -user SCOTT -password 
    TIGER
    & bindds /test/empDS -dstype jta
    
    
  2. Retrieve the DataSource in your code. When you perform the lookup, you must cast the returned object to OracleJTADataSource instead of DataSource. The Oracle-specific version of the DataSource class contains methods to set the DataSource properties.

  3. Set the following properties:

    • Set the URL with the OracleJTADataSource.setURL method

    • Fully-qualified database link if using two-phase commit engine with the OracleJTADataSource.setDBLink method

  4. Retrieve the connection through the OracleJTADataSource.getConnection method as indicated in the other examples.

Example 7-7 Retrieving Generic DataSource

The following example retrieves a generically bound DataSource from the namespace using in-session lookup and initializes all relevant fields.

//retrieve an in-session generic DataSource object
OracleJTADataSource ds =
(OracleJTADataSource)ic.lookup ("java:comp/env/test/empDS"); //set all relevant properties for my database //URL is for a local database so use the KPRB URL ds.setURL ("jdbc:oracle:kprb:"); //Used in two-phase commit, so provide the fully qualified database link that //was created from the two-phase commit engine to this database ds.setDBLink("localDB.oracle.com"); //Finally, retrieve a connection to the local database using the DataSource Connection conn = ds.getConnection ();

Setting the Transaction Timeout

A global transaction automatically has an idle timeout of 60 seconds. If the session attached to the transaction is idle for over the timeout limit, the transaction is rolled back. If any activity occurs within this timeframe, the timeout is reset to zero.

To initialize a different timeout, set the timeout value--in seconds--through the setTransactionTimeout method before the transaction is begun. If you change the timeout value after the transaction begins, it will not affect the current transaction. The following example sets the timeout to 2 minutes (120 seconds) before the transaction begins.

//create the initial context
InitialContext ic = new InitialContext ( );

//retrieve the UserTransaction object
ut = (UserTransaction)ic.lookup ("/test/myUT");

//set the timeout value to 2 minutes
ut.setTransactionTimeout (120);

//begin the transaction
ut.begin

//Update employee table with new employees
updateEmployees(emp, newEmp);

//end the transaction.
ut.commit ();

JTA Limitations

The following are the portions of the JTA specification that Oracle9i does not support.

Nested Transactions

Nested transactions are not supported in this release. If you attempt to begin a new transaction before committing or rolling back any existing transaction, the transaction service throws a NotSupportedException exception.

Interoperability

The transaction services supplied with this release do not interoperate with other JTA implementations.

Timeouts

The global transaction timeout does not work. In addition, the UserTransaction idle timeout (setTransactionTimeout method) starts only when a database connection is closed and idle. Oracle recommends that you do not use timeouts.

Java Transaction Service

With JTS, you demarcate the transaction off of a transaction context, which you can retrieve from the TransactionService object. The transaction context contains the begin, commit, rollback, suspend, and resume methods. One of the disadvantages to JTS is that you cannot use a two-phase commit engine to coordinate changes to multiple databases. The advantage to JTS is that you can suspend and resume the transaction. Also, because it is specific to CORBA, you can use either Java or non-Java languages in your application.

This implementation of JTS does not manage distributed transactions. Transaction control distributed among multiple database servers, with support for the required two-phase commit protocol, is only available within the JTA implementation.

The JTS transaction API supplied with Oracle9i manages only one resource: an Oracle9i database session. A transaction exists within only a single server, which means that it cannot span multiple servers or multiple database sessions in a single service. Transaction contexts are never propagated outside a server. If a server object calls out to another server, the transaction context is not carried along. However, a transaction can involve one or many objects. The transaction can encompass one or many methods within these objects.

Whether you demarcate the transaction on the client or the server, the following must occur:

  1. Initialize the TransactionService object.

    Oracle9i automatically initializes this object for any server objects; thus, only the client must explicitly initialize this object. The initialization is accomplished through the AuroraTransactionService.initialize method.

  2. Retrieve the TransactionService object through the static TS.getTS method.

  3. Retrieve the current transaction context through the TransactionService.getCurrent method.

  4. Manage the transaction through the following transaction context (Current class) methods: begin, commit, rollback, rollback_only, suspend, resume.

JTS Client-Side Demarcation

The only difference between client and server-side demarcation is that the client must initialize the TransactionService object before retrieving it. The client initializes a TransactionService object on the intended server. Since JTS can only manage a transaction within a single server, the client should invoke server objects that exist only on that single server. In addition, any SQL statements executed against the database should also be solely applied to the same server.

The following example demonstrates the steps required for a client-side demarcation:

  1. Initialize the TransactionService object. The initialization is accomplished through the AuroraTransactionService.initialize method.

  2. Retrieve the TransactionService object through the static TS.getTS method.

  3. Retrieve the current transaction context through the TransactionService.getCurrent method.

  4. Manage the transaction through the following transaction context (Current class) methods: begin, commit, rollback, rollback_only, suspend, resume.

Example 7-8 Client-Side Demarcation for JTS Example

import employee.*;
import oracle.aurora.jndi.sess_iiop.ServiceCtx;
import oracle.aurora.jts.client.AuroraTransactionService;
import oracle.aurora.jts.util.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.Hashtable;

public class Client
{
  public static void main (String[] args) throws Exception {
    if (args.length != 4) {
      System.out.println ("usage: Client serviceURL objectName user password");
      System.exit (1);
    }
    String serviceURL = args [0];
    String objectName = args [1];
    String user = args [2];
    String password = args [3];

    //The environment must be setup with the correct authentication 
    //and prefix information before you create the initial context
    Hashtable env = new Hashtable ();
    env.put (Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
    env.put (Context.SECURITY_PRINCIPAL, user);
    env.put (Context.SECURITY_CREDENTIALS, password);
    env.put (Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);
    Context ic = new InitialContext (env);

    //provide the intial context and the service URL of the server
    AuroraTransactionService.initialize (ic, serviceURL);

    //Since JTS can only manage transactions on a single server, the
    //destination server object exists on the same server as the transaction
    //service. Thus, you use the same service URL to retrieve the object.
    Employee employee = (Employee)ic.lookup (serviceURL + objectName);
    EmployeeInfo info;

    //Use the static method getTS to retrieve the TransactionService and the
    //static method getCurrent to retrieve the current transaction context.
    //Off of the Current object, you can start the transaction with the begin
    //method. All three methods have been combined as follows:
    TS.getTS ().getCurrent ().begin ();

    //invoke a method on the retrieved server object. Since the object exists
    //on the transaction server, it is included in the transaction.
    info = employee.getEmployee ("SCOTT");
    System.out.println (info.name + " "  + " " + info.salary);
    System.out.println ("Increase by 10%");
    info.salary += (info.salary * 10) / 100;
    employee.updateEmployee (info);
    info = employee.getEmployee ("SCOTT");
    System.out.println (info.name + " "  + " " + info.salary);

    //Finally, commit the transaction with the Current.commit method.
    TS.getTS ().getCurrent ().commit (true);
  }
}

JTS Server-Side Demarcation

Oracle9i initializes the TransactionService for any server object. In the same manner as the client, the server must invoke only other server objects on the same server. SQL statements should also only be applied to the same database.

The following example demonstrates the steps required for a client-side demarcation:

  1. Retrieve the TransactionService object through the static TS.getTS method.

  2. Retrieve the current transaction context through the TransactionService.getCurrent method.

  3. Manage the transaction through the following transaction context (Current class) methods: begin, commit, rollback, rollback_only, suspend, resume.

Example 7-9 Server-Side Demarcation for JTS Example

package employeeServer;

import employee.*;
import java.sql.*;
import oracle.aurora.jts.util.*;
import org.omg.CosTransactions.*;

public class EmployeeImpl extends _EmployeeImplBase
{
  Control txn;
  
  public EmployeeInfo getEmployee (String name) throws SQLError {
    //When the client invokes the getEmployee method, the transaction is started
    //Retreive the Transaction service through the static getTS method.
    //Retrieve the current transaction context through the getCurrent method.
    //And start the transaction with the Current.begin method. These have
    //been combined into one statement....
    TS.getTS ().getCurrent ().begin ();

    //Retrieve the employee information given the employee name.
    int empno = 0;
    double salary = 0.0;
    #sql { select empno, sal into :empno, :salary from emp
                    where ename = :name };

    //At this point, we suspend the transaction to return the employee
    //information to the client.
    txn = TS.getTS().getCurrent().suspend();
    return new EmployeeInfo (name, empno, (float)salary);
  }

  public void updateEmployee (EmployeeInfo employee) throws SQLError {
    //After the client retrieves the employee info, it invokes the updateEmp
    //method to change any values.
    //The transaction is resumed in this method through the Current.resume,
    //which requires the Control object returned on the suspend method.
    TS.getTS().getCurrent().resume(txn);

    //update the employee's information.
    #sql { update emp set ename = :(employee.name), sal = :(employee.salary)
                    where empno = :(employee.number) };

    //Once finished, complete the transaction with the Current.commit method.
    TS.getTS ().getCurrent ().commit (true);
 }

JTS Limitations

The implementations of JTS that is supplied for this Oracle9i release is intended to support client-side transaction demarcation. It has limitations that you should be aware of when designing your application.

No Distributed Transactions

This implementation of JTS does not manage distributed transactions. Transaction control distributed among multiple database servers, with support for the required two-phase commit protocol, is only available within the JTA implementation.

Resources

The JTS transaction API supplied with Oracle9i manages only one resource: an Oracle9i database session. A transaction cannot span multiple servers or multiple database sessions in a single service.

Transaction contexts are never propagated outside a server. If a server object calls out to another server, the transaction context is not carried along.

However, a transaction can involve one or many objects. The transaction can encompass one or many methods of these objects. The scope of a transaction is defined by a transaction context that is shared by the participating objects. For example, your client can invoke one or more objects on the same server within a single session or several objects on the same server within multiple sessions.

Nested Transactions

Nested transactions are not supported in this release. If you attempt to begin a new transaction before committing or rolling back any existing transaction, the transaction service throws a SubtransactionsUnavailable exception.

Timeouts

Methods of the JTS that support transaction timeout, such as setTimeout(), do not work in this release. You can invoke them from your code, and no exception is thrown, but they have no effect.

Interoperability

The transaction services supplied with this release do not interoperate with other OTS implementations.

Transaction Service Interfaces

Oracle9i supports a version of the JTS. The JTS is a Java mapping of the OMG Object Transaction Service (OTS). There are two classes that the application developer can use:

TransactionService

Use the TransactionService to initialize a transaction context on the client. Include the AuroraTransactionService package in your Java client source with the following import statements:

import oracle.aurora.jts.client.AuroraTransactionService;
import javax.jts.*;
import oracle.aurora.jts.util.*;

These classes are included in the library file aurora_client.jar, which must be in the CLASSPATH when compiling and executing all source files that use the JTS.

There is only one method in this package that you can call:

public synchronized static void initialize(Context initialContext,
                                           String serviceName)

This method initializes the transaction context on a client. The parameters are:

serviceName

The complete service name. For example sess_iiop://localhost:2481:ORCL

An example of using initialize() is:

Hashtable env = new Hashtable();
env.put(Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
env.put(Context.SECURITY_PRINCIPAL, "scott");
env.put(Context.SECURITY_CREDENTIALS, "tiger");
env.put(Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);
Context initialContext = new InitialContext(env);
AuroraTransactionService.initialize
          (initialContext, "sess_iiop://localhost:2481:ORCL");

Using The Java Transaction Service

JTS contains methods that a client-side or server-side object uses to begin transactions, commit or roll back a transaction, and perform utility functions such as setting the transaction timeout. JTS methods should be used in CORBA clients server objects.

The following sections describe the JTS APIs:

Required Import Statements

To use the JTS methods, include the following import statements in your source:

import oracle.aurora.jts.util.TS;
import javax.jts.util.*;
import org.omg.CosTransactions.*;

The oracle.aurora.jts.util package is included in the library file aurora_client.jar, which must be in the CLASSPATH for all Java sources that use the JTS.

You use the static methods in the TS class to retrieve the transaction service.

Java Transaction Service Methods

The JTS includes the following methods:

public static synchronized TransactionService getTS()

  1. The getTS method returns a transaction service object.

  2. Once a transaction service has been obtained, you can invoke the static method getCurrent() on it to return a Current pseudo-object, the transaction context.

  3. Finally, you can invoke methods to begin, suspend, resume, commit, or roll back the current transaction on the Current pseudo-object.

Here is an example that begins a new transaction on a client, starting with getting the JNDI initial context:

import oracle.aurora.jndi.sess_iiop.ServiceCtx;
import oracle.aurora.jts.client.AuroraTransactionService;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.Hashtable;
...
Context ic = new InitialContext(env);
...
AuroraTransactionService.initialize(ic, serviceURL);
...
Employee employee = (Employee)ic.lookup (serviceURL + objectName);
EmployeeInfo info;
oracle.aurora.jts.util.TS.getTS().getCurrent().begin();

If there is no transaction service available, then getTS() throws a NoTransactionService exception.

Current Transaction Methods

The methods that you can call to control transactions on the current transaction context are the following:

public void begin()

Begins a new transaction.

Can throw these exceptions:

See the section "TransactionService" for information about initialization.


public Control suspend()

Suspends the current transaction in the session. Returns a Control transaction context pseudo-object. You must save this object reference for use in any subsequent resume() invocations. Invoke suspend() in this way:

org.omg.CosTransactions.Control c =
          oracle.aurora.jts.util.TS.getTS().getCurrent().suspend();

suspend() can throw these exceptions:

If suspend() is invoked outside of a transaction context, then a NoTransactionService exception is thrown. If suspend() is invoked before begin() has been invoked, or after a suspend(), the a exception is thrown.


public void resume(Control which)

Resumes a suspended transaction. Invoke this method after a suspend(), in order to resume the specified transaction context. The which parameter must be the transaction Control object that was returned by the previous matching suspend() invocation in the same session. For example:

org.omg.CosTransactions.Control c = 
             oracle.aurora.jts.util.TS.getTS().getCurrent().suspend();
...   // do some non-transactional work
oracle.aurora.jts.util.TS.getTS().getCurrent().resume(c);

resume() can throw:

Commits the current transaction. Set the report_heuristics parameter to false.

The report_heuristics parameter is set to true for extra information on two-phase commits. Because this release of Oracle9i does not support the two-phase commit protocol for distributed objects for JTS, use of the report_heuristics parameter is not meaningful. It is included for compatibility with future releases.

commit() can throw:

The HeuristicMixed and HeuristicHazard exceptions are documented in the OTS specification.

If there is no active transaction, commit() throws a NoTransaction exception.


public void rollback()

Rolls back the effects of the current transaction.

Invoking rollback() has the effect of ending the transaction, so invoking any JTS method except begin() after a rollback() throws a NoTransaction exception.

If not in a transaction context, rollback() throws the NoTransaction exception.


public void rollback_only() throws NoTransaction {

rollback_only() modifies the transaction associated with the current thread so that the only possible outcome is to roll back the transaction. If not in a transaction context, rollback_only() throws the NoTransaction exception.


public void set_timeout(int seconds)

This method is not supported, and has no effect if invoked. The default timeout value is 60 seconds in all cases.


public Status get_status()

You can call get_status() at any time to discover the status of the current transaction. Possible return values are:

The complete set of status ints is defined in javax.transaction.Status.


public String get_transaction_name() {

Invoke get_transaction_name() to see the name of the transaction, returned as a String. If this method is invoked before a begin(), after a rollback(), or outside of a transaction context, it returns a null string.

For More Information on JTS

Information on the Java Transaction Service is available at:

http://java.sun.com:/products/jts/index.html

The Sun JTS specification is available at:

http://java.sun.com/products/jta/index.html

The OTS specification is part of the CORBA services specification. Chapter 10 (individually downloadable) contains the OTS specification. Get it at:

http://www.omg.org/library/csindx.html

JDBC Restrictions

If you are using JDBC calls in your CORBA server object to update a database, and you have an active transaction context, you should not also use JDBC to perform transaction services, by calling methods on the JDBC connection. Do not code JDBC transaction management methods. For example:

Connection conn = ...
...
conn.commit();  // DO NOT DO THIS!!

Doing so will cause a SQLException to be thrown. Instead, you must commit using the UserTransaction object retrieved to handle the global transaction. When you commit using the JDBC connection, you are instructing a local transaction to commit, not the global transaction. When the connection is involved in a global transaction, trying to commit a local transaction within the global transaction causes an error to occur.

In the same manner, you must also avoid doing direct SQL commits or rollbacks through JDBC. Code the object to either handle transactions directly using the UserTransaction interface.

Within a global transaction, you cannot execute a local transaction. If you try, the following error will be thrown:

ORA-2089 "COMMIT is not allowed in a subordinate session."

Some SQL commands implicitly execute a local transaction. All SQL DDL statements, such as "CREATE TABLE", implicitly starts and commits a local transaction under the covers. If you are involved in a global transaction that has enlisted the database that the DDL statement is executing against, the global transaction will fail.


Go to previous page Go to next page
Oracle
Copyright © 1996-2001, Oracle Corporation.

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

Master Index

Feedback