Skip Headers

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

Previous | Next |

# Unit of Work Concepts

This section introduces transaction concepts unique to TopLink, including the following:

- Unit of Work Benefits

- Unit of Work Life Cycle

- Unit of Work and Change Policy

- Clones and the Unit of Work

- Nested and Parallel Units of Work

- Commit and Rollback Transactions

- Primary Keys

- Unit of Work Optimization

- Example Model Object and Schema

## Unit of Work Benefits

The TopLink unit of work simplifies transactions and improves transactional performance. It is the preferred method of writing to a database in TopLink because it performs the following:

- Sends a minimal amount of SQL to the database during the commit by updating only the exact changes down to the field level

- Reduces database traffic by isolating transaction operations in their own memory space

- Optimizes cache coordination, in applications that use multiple caches, by passing change sets (rather than objects) between caches

- Isolates object modifications in their own transaction space to allow parallel transactions on the same objects

- Ensures referential integrity and minimizes deadlocks by automatically maintaining SQL ordering

- Orders database insert, update, and delete operations to maintain referential integrity for mapped objects

- Resolves bidirectional references automatically

- Frees the application from tracking or recording its changes

- Simplifies persistence with persistence by reachability (see "Associating a New Source to an Existing Target Object")

## Unit of Work Life Cycle

TopLink uses the unit of work as follows:

1. The client application acquires a unit of work from a session object.

2. The client application queries TopLink to obtain a cache object it wants to modify, and then registers the cache object with the unit of work.

3. The unit of work registers the object according to the object's change policy. For more information about how change policy affects registration, see "Unit of Work and Change Policy".

   By default, as each object is registered, the unit of work accesses the object from the session cache or database and creates a backup clone and working clone (see "Clones and the Unit of Work"). The unit of work returns the working clone to the client application.

4. The client application modifies the working object returned by the unit of work.

5. The client application (or external transaction controller) commits the transaction.

6. The unit of work calculates the change set for each registered object according to the object's change policy. For more information about how change policy affects change set calculation, see "Unit of Work and Change Policy".

   By default, at commit time, the unit of work compares the working clones to the backup clones and calculates the change set (that is, determines the minimum changes required). The comparison is done with a backup clone so that concurrent changes to the same objects will not result in incorrect changes being identified. The unit of work then attempts to commit any new or changed objects to the database.

   If the commit transaction succeeds, the unit of work merges changes into the shared session cache. Otherwise, no changes are made to the objects in the shared cache. For more details, see "Commit and Rollback Transactions".

   If there are no changes, the unit of work does not start a new transaction.

Figure 100-1 The Life Cycle of a Unit of Work

Description of "Figure 100-1 The Life Cycle of a Unit of Work"

Example 100-1 shows the default life cycle in code.

Example 100-1 Unit of Work Life Cycle

    // The application reads a set of objects from the database
    Vector employees = session.readAllObjects(Employee.class);

    // The application specifies an employee to edit
    . . .
    Employee employee = (Employee) employees.elementAt(index);

    try {
        // Acquire a unit of work from the session
        UnitOfWork uow = session.acquireUnitOfWork();
        // Register the object that is to be changed. Unit of work returns a clone
        // of the object and makes a backup copy of the original employee
        Employee employeeClone = (Employee)uow.registerObject(employee);
        // Make changes to the employee clone by adding a new phoneNumber.
        // If a new object is referred to by a clone, it does not have to be
        // registered. Unit of work determines it is a new object at commit time
        PhoneNumber newPhoneNumber = new PhoneNumber("cell","212","765-9002");
        employeeClone.addPhoneNumber(newPhoneNumber);
        // Commit the transaction: unit of work compares the employeeClone with
        // the backup copy of the employee, begins a transaction, and updates the
        // database with the changes. If successful, the transaction is committed
        // and the changes in employeeClone are merged into employee. If there is an
        // error updating the database, the transaction is rolled back and the
        // changes are not merged into the original employee object
        uow.commit();
    } catch (DatabaseException ex) {
        // If the commit fails, the database is not changed. The unit of work should
        // be thrown away and application-specific action taken
    }
    // After the commit, the unit of work is no longer valid. Do not use further

## Unit of Work and Change Policy

The unit of work tracks changes for a registered object based on the change policy you configure for the object's descriptor. If there are no changes, the unit of work will not start a new transaction.

Table 100-2 lists the change policies that TopLink provides.

Table 100-2 TopLink Change Policies

Change Policy | Applicable to...
--- | ---
``Deferred Change Detection Policy | Wide range of object change characteristics. The default change policy.
``Object-Level Change Tracking Policy | Objects with few attributes or with many attributes and many changed attributes.
``Attribute Change Tracking Policy | Objects with many attributes and few changed attributes. The most efficient change policy. The default change policy for EJB 3.0 or 2.x CMP on OC4J.

For more information, see "Configuring Change Policy".

### Deferred Change Detection Policy

The `DeferredChangeDetectionPolicy` is the change policy that all persistent objects use by default.

This option provides good unit of work commit performance for a wide range of object change characteristics.

When you register in a unit of work an object whose descriptor is configured with a `DeferredChangeDetectionPolicy` (see "Configuring Deferred Change Detection Policy"), a backup clone is made of the object (see "Clones and the Unit of Work") and at commit time, the unit of work computes changes by making an attribute-by-attribute comparison between the backup clone and the original object.

This change policy is applicable to all mapping types.

### Object-Level Change Tracking Policy

The `ObjectChangeTrackingPolicy` optimizes the unit of work commit transaction by including objects in the change set calculation only if at least one attribute has changed.

This option provides improved unit of work commit performance for objects with few attributes, or with many attributes and many changed attributes.

When you register in a unit of work an object whose descriptor is configured with `ObjectChangeTracking` change policy, a backup clone is made of the object and at commit time, the unit of work computes changes by comparing the backup to the current object if and only if at least one attribute is changed (if the object's `hasChanges` method returns `true`). If a registered object has no changes, the unit of work does not compare it to the backup clone.

This change policy is applicable to a subset of mapping types (see "Change Policy Mapping Support").

TopLink provides different levels of support for this change policy depending on the EBJ version and application server you are using:

#### EJB 2.n or 3.0 CMP

For EJB 2.0 or 3.0 CMP applications deployed to an application server for which TopLink provides CMP integration (see "Application Server Support"), when you configure a CMP entity bean's descriptor with an `ObjectChangeTrackingPolicy`, TopLink code generates a concrete subclass to implement the TopLink `ChangeTracker` interface at deploy time (see "Configuring Object Change Tracking Policy").

#### EJB 1.n CMP and Plain Java Objects

For EJB 1.n CMP on any application server or plain Java objects, you must implement the `ChangeTracker` interface for each persistent class and configure the class's descriptor with an `ObjectChangeTrackingPolicy` (see "Configuring Object Change Tracking Policy").

### Attribute Change Tracking Policy

The `AttributeChangeTrackingPolicy` optimizes the unit of work commit transaction by tracking all object changes at the attribute level. This eliminates two unit of work operations: backup clone creation and change detection through comparison.

This option provides improved unit of work commit performance for objects with many attributes, and few changed attributes. Generally, this is the most efficient change policy.

This change policy is applicable to a subset of mapping types (see "Change Policy Mapping Support").

Note: You cannot use the `AttributeChangeTrackingPolicy` if you are using any instance of `FieldsLockingPolicy` (see "Optimistic Field Locking Policies").

TopLink provides different levels of support for this change policy depending on the EBJ version and application server you are using:

#### EJB 3.0 or 2.n CMP on OC4J

When using EJB 3.0 or 2.n CMP on OC4J, if you want to benefit from this performance enhancement, configure your descriptors with the default `DeferredChangeDetectionPolicy` and allow TopLink to automatically apply an `AttributeChangeTrackingPolicy`. If you configure your project's descriptors with any other change policy, TopLink will honor that configuration and not apply an `AttributeChangeTrackingPolicy`.

When you deploy a TopLink-enabled EJB 3.0 CMP application to OC4J, for each mapped class configured with the default `DeferredChangeDetectionPolicy`, TopLink uses bytecode weaving to automatically override this configuration with an `AttributeChangeTrackingPolicy` and to make the class implement the required interfaces.

When you deploy a TopLink-enabled EJB 2.x CMP application to OC4J, for each mapped class configured with the default `DeferredChangeDetectionPolicy`, TopLink uses code generation to automatically override this configuration with an `AttributeChangeTrackingPolicy` and to make the class implement the required interfaces.

#### EJB 1.n CMP, Plain Java Objects, or Other Application Servers

For EJB 1.n CMP, plain Java objects, or application servers other than OC4J, to use the `AttributeChangeTrackingPolicy` with a class, you must configure the class's descriptor with an `AttributeChangeTrackingPolicy` and you must implement the `ChangeTracker` interface in that class (see "Configuring Attribute Change Tracking Policy").

### Change Policy Mapping Support

TopLink supports alternative change tracking policies (policies other than `DeferredChangeDetectionPolicy`) for attributes that use any of the following mapping types:

- Direct-to-Field Mapping

- Transformation Mapping (immutable mappings only)

- One-to-One Mapping

- One-to-Many Mapping

- Many-to-Many Mapping

- Direct Collection Mapping

- Direct Map Mapping

- Aggregate Object Mapping

- EIS Composite Object Mapping

- EIS Transformation Mapping (immutable mappings only)

- XML Composite Object Mapping

- XML Transformation Mapping (immutable mappings only)

TopLink uses the `DeferredChangeDetectionPolicy` (see "Deferred Change Detection Policy") for attributes that use any other type of mapping.

## Clones and the Unit of Work

When using the `DefrerredChangeDetectionPolicy` or the `ObjectLevelChangeTrackingPolicy` (see "Deferred Change Detection Policy"), the unit of work maintains two copies of the original objects registered with it:

- Working clones

- Backup clones

After you change the working clones and the transaction is committed, the unit of work compares the working clones to the backup clones, and writes any changes to the database. The unit of work uses clones to allow parallel units of work (see "Nested and Parallel Units of Work") to exist, a requirement in multiuser three-tier applications.

The TopLink cloning process is efficient in that it clones only the mapped attributes of registered objects, and stops at indirection objects unless you trigger the indirection. For more information, see "Configuring Indirection".

You can customize the cloning process using the descriptor's copy policy. For more information, see "Configuring Copy Policy".

Never use a clone after committing the unit of work that the clone is from (even if the transaction fails and rolls back). A clone is a working copy used during a transaction and as soon as the transaction is committed (successful or not), the clone must not be used. Accessing an uninstantiated clone value holder after a unit of work commit transaction will raise an exception. The only time you can use a clone after a successful commit transaction is when you use the advanced API described in "Resuming a Unit of Work After Commit".

## Nested and Parallel Units of Work

You can use TopLink to create the following:

- Nested Unit of Work

- Parallel Unit of Work

For additional information and examples on using nested and parallel units of work, see "Using a Nested or Parallel Unit of Work".

### Nested Unit of Work

You can nest a unit of work (the child) within another unit of work (the parent). A nested unit of work does not commit changes to the database. Instead, it passes its changes to the parent unit of work, and the parent attempts to commit the changes at commit time. Nesting units of work lets you break a large transaction into smaller isolated transactions, and ensures that:

- Changes from each nested unit of work commit or fail as a group.

- Failure of a nested unit of work does not affect the commit or rollback transaction of other operations in the parent unit of work.

- Changes are presented to the database as a single transaction.

### Parallel Unit of Work

You can modify the same objects in multiple unit of work instances in parallel because the unit of work manipulates copies of objects. TopLink resolves any concurrency issues when the Units of Work commits the changes.

## Commit and Rollback Transactions

When a unit of work transaction is committed, it either succeeds, or fails and rolls back. A commit transaction can be initiated by your application or by a J2EE container.

### Commit Transactions

At commit time, the unit of work compares the working clones and backup clones to calculate the change set (that is, to determine the minimum changes required). Changes include updates to or deletion of existing objects, and the creation of new objects. The unit of work then begins a database transaction, and attempts to write the changes to the database. If all changes commit successfully on the database, the unit of work merges the changed objects into the session cache. If any one of the changes fail on the database, the unit of work rolls back any changes on the database, and does not merge changes into the session cache.

The unit of work calculates commit order using foreign key information from one-to-one and one-to-many mappings. If you encounter constraint problems during a commit transaction, verify your mapping definitions. The order in which you register objects with the `registerObject` method does not affect the commit order.

#### Commit and JTA

When your application uses JTA, the unit of work commit transaction acts differently than in a non-JTA application. In most cases, the unit of work attaches itself to an external transaction. If no transaction exists, the unit of work creates a transaction. This distinction affects commit activity as follows:

- If the unit of work attaches to an existing transaction, the unit of work ignores the `commit` call. The transaction commits the unit of work when the entire external transaction is complete.

- If the unit of work starts the external transaction, the transaction treats the unit of work `commit` call as a request to commit the external transaction. The external transaction then calls its own commit code on the database.

In either case, only the external transaction can call `commit` on the database because it owns the database connection.

For more information, see "Integrating the Unit of Work With an External Transaction Service".

### Rollback Transactions

A unit of work commit transaction must succeed or fail as a unit. Failure in writing changes to the database causes the unit of work to roll back the database to its previous state. Nothing changes in the database, and the unit of work does not merge changes into the session cache.

#### Rollback and JTA

In a JTA environment, the unit of work does not own the database connection. In this case, the unit of work sends the rollback call to the external transaction rather than the database, and the external transaction treats the rollback call as a request to roll the transaction back.

For more information, see "Integrating the Unit of Work With an External Transaction Service".

## Primary Keys

You cannot modify the primary key attribute of an object in a unit of work. This is an unsupported operation and doing so will result in unexpected behaviour (exceptions or database corruption).

To replace one instance of an object with unique constraints with another, see "Using the Unit of Work setShouldPerformDeletesFirst Method".

## Unit of Work Optimization

By default, the unit of work performs change set calculation efficiently for a wide range of object change characteristics. However, there are various ways you can use the unit of work to enhance application performance.

One way to improve performance is to consider using an alternative change policy (see "Unit of Work and Change Policy").

For more performance options, see "Unit of Work Optimization".