Skip Headers

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

Previous | Next |

# Understanding Descriptors and Locking

This section describes the various types of locking policy that TopLink supports, including the following:

- Optimistic Version Locking Policies

- Optimistic Version Locking Policies and Cascading

- Optimistic Field Locking Policies

- Pessimistic Locking Policy

- Locking in a Three-Tier Application

For more information, see "Configuring Locking Policy".

## Optimistic Version Locking Policies

With optimistic locking, all users have read access to the data. When a user attempts to make a change, the application checks to ensure the data has not changed since the user read the data.

Optimistic version locking policies enforce optimistic locking by using a version field (also known as a write-lock field) that you provide in the reference class that TopLink updates each time an object change is committed.

TopLink caches the value of this version field as it reads an object from the data source. When the client attempts to write the object, TopLink compares the cached version value with the current version value in the data source in the following way:

- If the values are the same, TopLink updates the version field in the object and commits the changes to the data source.

- If the values are different, the write operation is disallowed because another client must have updated the object since this client initially read it.

TopLink provides the following version-based optimistic locking policies:

- `VersionLockingPolicy`: requires a numeric version field; TopLink updates the version field by incrementing its value by one.

- `TimestampLockingPolicy`: requires a timestamp version field; TopLink updates the version field by inserting a new timestamp (this policy can be configured to get the time from the data source or locally; by default, the policy gets the time from the data source).

Note: In general, Oracle recommends numeric version locking, because: accessing the timestamp from the data source can cause a performance issue time stamp locking is limited to the precision that the database stores for timestamps

Whenever any update fails because optimistic locking has been violated, TopLink throws an `OptimisticLockException`. This should be handled by the application when performing any database modification. The application must notify the client of the locking contention, refresh the object, and have the client reapply its changes.

You can choose to store the version value in the object as a mapped attribute, or in the cache. In three-tier applications, you typically store the version value in the object to ensure it is passed to the client when updated (see "Locking in a Three-Tier Application").

If you store the version value in the cache, you do not need to map it. If you do map the version field, you must configure the mapping as read-only (see "Configuring Read-Only Mappings").

To ensure that the parent object's version field is updated whenever a privately owned child object is modified, consider "Optimistic Version Locking Policies and Cascading".

When using optimistic version locking with the unit of work, consider "Using Optimistic Read Locking with forceUpdateToVersionField".

## Optimistic Version Locking Policies and Cascading

If your database schema is such that both a parent object and its privately owned child object are stored in the same table, then if you update the child object, the parent object's version field will be updated.

However, if the parent and its privately owned child are stored in separate tables, then changing the child will not, by default, update the parent's version field.

To ensure that the parent object's version field is updated in this case, you can either manually update the parent object's version field (see "Using Optimistic Read Locking with forceUpdateToVersionField") or, if you are using a `TimestampLockingPolicy`, you can configure TopLink to automatically cascade the child object's version field update to the parent (see "Configuring Optimistic Locking Policy Cascading").

After you enable optimistic version locking cascading, when a privately owned child object is modfied, TopLink will traverse the privately owned foreign reference mappings, updating all the parent objects back to the root.

Optimistic version locking cascading is only applied if the child object is registered in a unit of work.

TopLink supports optimistic version locking cascading for:

- object changes in privately owned one-to-one and one-to-many mappings

- relationship changes (adding or removing) in the following collection mappings (privately owned or not):

  - direct collection

  - one-to-many

  - many-to-many

  - aggregate collection

Consider the example object graph shown in Figure 26-5

Figure 26-5 Optimistic Version Locking Policies and Cascading Example

Description of "Figure 26-5 Optimistic Version Locking Policies and Cascading Example"

In this example, `ObjectA` privately owns `ObjectB`, and `ObjectB` privately owns `ObjectC`, and `ObjectC` privately owns `ObjectD`.

Suppose you register `ObjectB` in a unit of work, modify an `ObjectB` field, and commit the unit of work. In this case, `ObjectB` checks the cache for `ObjectA` and, if not present, queries the database for `ObjectA`. `ObjectB` then notifies `ObjectA` of its change. `ObjectA` forces an update on its version optimistic locking field even though it has no changes to its corresponding table.

Suppose you register `ObjectA` in a unit of work, access its `ObjectB` to access its `ObjectC` to access its `ObjectD`, modify an `ObjectD` field, and commit the unit of work. In this case, `ObjectD` notifies `ObjectC` of its changes. `ObjectC` forces an update on its version optimistic locking field even though it has no changes to its corresponding table. `ObjectC` then notifies `ObjectB` of the `ObjectD` change. `ObjectB` then notifies `ObjectA` of the `ObjectD` change. `ObjectA` forces an update on its version optimistic locking field even though it has no changes to its corresponding table.

## Optimistic Locking and Rollbacks

With optimistic locking, use the `UnitOfWork` method `commitAndResumeOnFailure` (see "Resuming a Unit of Work After Commit") to rollback a locked object's value, if you store the optimistic lock versions in the cache.

If you store the locked versions in an object, you must refresh the objects (or their versions) on a failure. Alternatively, you can acquire a new unit of work on the failure and reapply any changes into the new unit of work.

## Optimistic Field Locking Policies

Optimistic field locking policies enforce optimistic locking by using one or more of the fields that currently exist in the table to determine if the object has changed since the client read the object.

The unit of work caches the original state of the object when you first read the object or register it with the unit of work. At commit time, the unit of work compares the original values of the lock fields with their current values on the data source during the update. If any of the lock field's values have changed, an optimistic lock exception is thrown.

TopLink provides the following optimistic field locking policies:

- `AllFieldsLockingPolicy`: For update and delete operations, TopLink compares all the fields of the object with all the fields in the data source. If the original value of any fields differ from that in the data source, the write operation is disallowed.

  For example, if you changed a customer's last name, TopLink might produce SQL like:

      UPDATE CUSTOMER SET LNAME='new last name' WHERE ID=7 AND LNAME='old last name' AND FNAME='Donald' AND B_DAY='1972' AND CREDIT_RATING='A+' AND EYE_COLOR='Blue'

  The main disadvantage of this field locking policy is that it is not the most efficient, especially if the changed object has many attributes.

  Note: This comparison is only on a per table basis. If an update operation is performed on an object that is mapped to multiple tables (multiple table inheritance), then only the changed fields for each table changed appear in the `where` clause.

- `ChangedFieldsLockingPolicy`: For update operations, TopLink compares only the fields of the object that have changed with the corresponding fields in the data source. If the original value of any such field differs from that in the data source, the write operation is disallowed. TopLink does not make any field comparisons for deletes.

  The main advantage of this field locking policy is that it allows concurrent updates of different fields. For example, if one thread updates a customer's last name and another thread updates the same customer's credit rating, and you configure the `Customer` descriptor with `ChangedFieldsLockingPolicy`, then TopLink might produce SQL like:

      // Unit of Work 1
      UPDATE CUSTOMER SET LNAME='new name' WHERE ID=7 AND LNAME='old name'
      // Unit of Work 2
      UPDATE CUSTOMER SET CREDIT_RATING='B' WHERE ID=7 AND CREDIT_RATING='A+'

- `SelectedFieldsLockingPolicy`: For update and delete operations, TopLink compares only the selected fields of the object with the corresponding fields in the data source. If the cached value of any such field differs from that in the data source, the write operation is disallowed.

  For example, if you select `Customer` attributes `LNAME` and `CREDIT_RATING`, then at run time, TopLink might produce SQL like:

      UPDATE CUSTOMER SET LNAME='new name' WHERE ID=7 AND LNAME='old name' AND CREDIT_RATING='A+'

Whenever any update fails because optimistic locking has been violated, TopLink throws an `OptimisticLockException`. This should be handled by the application when performing any database modification. The application must notify the client of the locking contention, refresh the object, and have the client reapply its changes.

When using field locking policies, a unit of work must be employed for updating the data source.

Note: You cannot use an instance of `FieldsLockingPolicy` if you are using `AttributeChangeTrackingPolicy` (see "Attribute Change Tracking Policy").

## Pessimistic Locking Policy

With pessimistic locking, the first user who accesses the data with the purpose of updating it locks the data until completing the update.

When using a pessimistic locking policy, you can configure the policy to either fail immediately or to wait until the read lock is acquired.

You can use a pessimistic locking policy only in a project with a persistence type of CMP (see "Configuring Persistence Type") and with descriptors that have EJB information (see "Configuring a Descriptor With EJB Information").

You can also use pessimistic locking (but not a pessimistic locking policy) at the query level (see "Configuring Named Query Options").

## Locking in a Three-Tier Application

If you are building a three-tier application, in order to correctly lock an object, you must obtain the lock before the object is sent to client for editing.

### Optimistic Locking in a Three-Tier Application

If you are using optimistic locking, you have two choices for locking objects correctly:

1. Map the optimistic lock field in your object as not read-only and pass the version to the client on the read and back to the server on the update.

   You must define a non-read-only mapping for the version field and make the optimistic locking policy store the version value in the object, not the cache (in TopLink Workbench, this is done on the Locking tab by unchecking Store Version in Cache: see "Using TopLink Workbench").

   Ensure that the original version value is sent to the client when it reads the object for the update. The client must then pass the original version value back with the update information, and this version must be set into the object to be updated after it is registered/read in the new unit of work on the server.

2. Hold the unit of work for the duration of the interaction with the client.

   Either through a stateful session bean, or in an HTTP session, store the unit of work used to read the object for the update for the duration of the client interaction.

   Your must read the object through this unit of work before passing it to the client for the update. This ensures that the version value stored in the unit of work cache or in the unit of work clone will be the original value.

   This same unit of work must be used for the update.

The first option is more commonly used, and is required if developing a stateless application.

### Pessimistic Locking in a Three-Tier Application

If you are using pessimistic locking, you must use the unit of work to start a database transaction before the object is read. You must hold this unit of work and database transaction while the client is editing the object and until the client updates the object. You must use this same unit of work to update the object. If you are building a three-tier Web application (where it is not normally desirable to hold a database transaction open across client interactions), optimistic locking is normally more desirable than pessimistic locking (see "Optimistic Locking in a Three-Tier Application").