Skip Headers

Oracle TopLink Developer's Guide 10g Release 3 (10.1.3) B13593-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# Integrating the Unit of Work With an External Transaction Service

To support transactions managed by an application server's external transaction service, TopLink supports external connection pools and external transaction controller classes for supported servers. This lets you incorporate external transaction service support into your application, and use the unit of work with transactions managed externally by the server. For more information, see "Unit of Work Transaction Demarcation".

To integrate a unit of work with an external transaction service, you must enable the use of an:

- external transaction controller (see "Configuring the Server Platform")

- external connection pool (see "Configuring External Connection Pooling")

After you configure external connection pool and external transaction controller support, you use a unit of work in your TopLink application as you would typically, with few exceptions. This section describes these exceptions as follows:

- Acquiring a Unit of Work with an External Transaction Service

- Using a Unit of Work When an External Transaction Exists

- Using a Unit of Work When No External Transaction Exists

- Using the Unit of Work to Handle External Transaction Timeouts and Exceptions

## Acquiring a Unit of Work with an External Transaction Service

You use a unit of work to commit changes to a data source even when using an external transaction service. To ensure that only one unit of work is associated with a given transaction, use the `getActiveUnitOfWork` method to acquire a unit of work as shown in Example 102-15.

Note: Although there are other ways to commit changes to a data source using an external transaction service, Oracle recommends using the `getActiveUnitOfWork` method.

The `getActiveUnitOfWork` method searches for an existing external transaction:

- If there is an active external transaction and a unit of work is already associated with it, return this unit of work.

- If there is an active external transaction with no associated unit of work, then acquire a new unit of work, associate it with the transaction, and return it.

- If there is no active external transaction in progress, return null.

If TopLink returns a unit of work that is not `null`, use it exactly as you would typically: the only exception is that you do not call the `commit` method (see "Using a Unit of Work When an External Transaction Exists").

If TopLink returns a `null` unit of work, start an external transaction either explicitly through the `UserTransaction` interface, or by acquiring a new unit of work using the `acquireUnitOfWork` method on the client session (see "Using a Unit of Work When No External Transaction Exists").

Example 102-15 Using a Unit of Work With an External Transaction Service

    // Read in any pet
    Pet pet = (Pet)clientSession.readObject(Pet.class);
    UnitOfWork uow = clientSession.getActiveUnitOfWork();
        if (uow == null) {
            uow = clientSession.acquireUnitOfWork(); // Start external transaction
        }
        Pet petClone = (Pet) uow.registerObject(pet);
        petClone.setName("Furry");
        uow.commit(); // Ask external transaction controller to commit
                      // Ignored if transaction not started by TopLink

## Using a Unit of Work When an External Transaction Exists

When `getActiveUnitOfWork` returns a unit of work that is not `null`, you are associated with an existing external transaction. Use the unit of work as usual.

As the external transaction was not started by the unit of work, issuing a `commit` on it will not cause the external transaction to be committed. The unit of work will defer to the application or container that began the transaction. When the external transaction does get committed by the container, TopLink receives synchronization callbacks at key points during the commit transaction.

The unit of work sends the required SQL to the database when it receives the `beforeCompletion` callback.

The unit of work uses the Boolean argument received from the `afterCompletion` callback to determine if the commit was successful (true) or not (false).

If the commit transaction was successful, the unit of work merges changes to the session cache. If the commit transaction was unsuccessful, the unit of work discards the changes.

Figure 102-2 shows the life cycle of a unit of work when an external transaction exists.

Figure 102-2 Unit of Work When an External Transaction Exists

Description of "Figure 102-2 Unit of Work When an External Transaction Exists"

## Using a Unit of Work When No External Transaction Exists

When the `getActiveUnitOfWork` method returns a null unit of work, there is no existing external transaction. You must start a new external transaction.

Do this either by starting an external transaction explicitly using the `UserTransaction` interface, or by acquiring a new unit of work using the `acquireUnitOfWork` method on the server session.

Use the unit of work as usual.

Once the modifications to registered objects are complete, you must commit the transaction either explicitly through the `UserTransaction` interface or by calling the unit of work `commit` method.

The transaction synchronization callbacks are then invoked on, and the database updates and cache merge occur based upon those callbacks.

Figure 102-3 Unit of Work When No External Transaction Exists

Description of "Figure 102-3 Unit of Work When No External Transaction Exists"

## Using the Unit of Work to Handle External Transaction Timeouts and Exceptions

This section describes two common problems with external transactions:

- External Transaction Commit Timeouts

- External Transaction Commit Exceptions

### External Transaction Commit Timeouts

When an external transaction is committed, the external transaction service expects each transaction owner to commit its portion of the overall transaction within a finite amount of time. If any individual transaction exceeds this timeout interval, the external transaction service will fail the specific transaction and roll it back (or mark it rollback only).

If your transaction is large and its commit transaction may exceed the external transaction service timeout interval, use `UnitOfWork` method `writeChanges` to write changes to the data source before committing the external transaction. This will reduce the time it takes for your part of the global transaction to commit.

For more information about the `UnitOfWork` method `writeChanges`, including restrictions and warnings, see "Writing Changes Before Commit Time".

### External Transaction Commit Exceptions

When you use the unit of work with an external transaction service, commit exceptions may not be thrown until long after your application thread calls its `UnitOfWork` method `commit` and returns. In this case, commit exceptions are thrown to the client of the container-managed transaction (CMT) call, forcing the client to handle this server-side failure.

You can use the `UnitOfWork` method `writeChanges` to write changes to the data source before the external transaction commits. This allows your application thread to catch and handle most exceptions that could be thrown at the time the external transaction service commits the global transaction.

For more information about the `UnitOfWork` method `writeChanges`, including restrictions and warnings, see "Writing Changes Before Commit Time".

For more information on handling unit of work exceptions in general, see "Handling Exceptions".