Skip Headers
Oracle TopLink Developer's Guide
10g Release 3 (10.1.3)
B13593-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

Using Optimistic Read Locking with forceUpdateToVersionField

If your descriptors are configured to use an optimistic version locking policy (see "Optimistic Version Locking Policies") or field locking policy (see "Optimistic Field Locking Policies"), use the unit of work method forceUpdateToVersionField to solve either or both of the following problems:

To remove forceUpdateToVersionField configuration from an object before a commit operation, use the unit of work method removeForceUpdateToVersionField (see "Disabling forceUpdateToVersionField").

Forcing a Check of the Optimistic Read Lock

When you read an object with the unit of work, optimistic lock checking is not applied to that object at commit time unless you change the object. However, there are times when you want your transaction to fail if the state of an object has changed since it was read, even though you have not modified the object.

Example 102-12 shows a transaction that updates a mortgage rate by multiplying the central bank prime rate by 1.25. The transaction forces an optimistic read lock on the central prime rate at commit time to ensure that the prime rate has not changed since the transaction began. Note that in this example, the transaction does not increment the version of the unchanged object (the central prime rate).

Example 102-12 Optimistic Read Lock with No Version Increment

try {
    UnitOfWork uow = session.acquireUnitOfWork();
    MortgageRate cloneMortgageRate = (MortgageRate)
      uow.registerObject(mortgageRate);
    CentralPrimeRate cloneCentralPrimeRate = (CentralPrimeRate)
      uow.registerObject(CentralPrimeRate);
    /* Change the Mortgage Rate */
    cloneMortgageRate.setRate(cloneCentralPrimeRate.getRate() * 1.25);
    /* Optimistic read lock check on Central prime rate with no version update */
    uow.forceUpdateToVersionField(cloneCentralPrimeRate, false);
    uow.commit();
} catch(OptimisticLockException exception) {
    /* Refresh the out-of-date object */
    session.refreshObject(exception.getObject());
    /* Retry… */
}

For another example that forces both optimistic locking and a version field update, see Example 102-13 in "Forcing a Version Field Update".

Forcing a Version Field Update

The unit of work considers an object changed when you modify its direct-to-field or aggregate object mapping attribute. Adding, removing, or modifying objects related to the source object does not render the source object changed for the purposes of the unit of work. In other words, when a relationship is changed in a one-to-many or one-to-one target foreign key mapping, by default, the version field (if any) of the affected object is not changed.

If you configure a descriptor to refresh the cache only if the database version is newer than the cache version (using descriptor method onlyRefreshCacheIfNewerVersion), and such a relationship changes, you will not be able to refresh the object at all. Because the version has not changed, the unit of work method refreshObject and even a query with refreshIdentityMapResults option set to true cannot refresh the object.

Using the unit of work method forceUpdateToVersionField passing in both the unit of work copy clone and true value will ensure that the object's version field is updated when such a change is made. It will also ensure that changes to the object before it is refreshed will result in optimistic locking exceptions, preventing the writing of stale data (see "Forcing a Check of the Optimistic Read Lock").

Example 102-13 and Example 102-14 show transactions executing in separate threads that access the same customer object concurrently. The unit of work method forceUpdateToVersionField is used to ensure that changes to the customer object in one thread are detected by the other threads.

Example 102-13 shows a transaction in which an invoice thread calculates an invoice for a customer. Example 102-14 shows a transaction in which another thread, the service thread, adds a service to the same customer or modifies the current service. In either case, the service thread must inform the invoice thread, which adds the changes to the invoice.

Example 102-13 Optimistic Read Lock with Version Increment: Service Thread

/* The following code represents the service thread. Notice that the thread forces a version update */
try {
    UnitOfWork uow = session.acquireUnitOfWork();
    Customer cloneCustomer = (Customer uow.registerObject(customer);
    Service cloneService = (Service uow.registerObject(service);
    /* Add a service to customer */
    cloneService.setCustomer(cloneCustomer);
    cloneCustomer.getServices().add(cloneService);
    /* Modify the customer version to inform other application that 
      the customer has changed */
    uow.forceUpdateToVersionField(cloneCustomer, true);
    uow.commit();
}
catch (OptimisticLockException exception) {
    /* Refresh out-of-date object */
    session.refreshObject(exception.getObject());
    /* Retry… */
}

Example 102-14 Optimistic Read Lock with Version Increment: Invoice Thread

/* The following code represents the invoice thread, and calculates a bill for the customer. Notice that it does not force an update to the version */

try {
    UnitOfWork uow = session.acquireUnitOfWork();
    Customer cloneCustomer = (Customer) uow.registerObject(customer);
    Invoice cloneInvoice = (Invoice) uow.registerObject(new Invoice());
    cloneInvoice.setCustomer(cloneCustomer);
    /* Calculate service charge */
    int total = 0;
    for(Enumeration enum = cloneCustomer.getServices().elements();     enum.hasMoreElements();) {
    total += ((Service) enum.nextElement()).getCost();
    }
    cloneInvoice.setTotal(total);
    /* Force optimistic lock checking on the customer to guarantee a valid 
      calculation */
    uow.forceUpdateToVersionField(cloneCustomer, false);
    uow.commit();
}
catch(OptimisticLockException exception) {
    /* Refresh the customer and its privately owned parts */
    session.refreshObject(cloneCustomer);
    /* If the customer's services are not privately owned then use a     ReadObjectQuery to refresh all parts */
    ReadObjectQuery query = new ReadObjectQuery(customer);
    /* Refresh the cache with the query's result and cascade refreshing 
      to all parts including customer's services */
    query.refreshIdentityMapResult();
    query.cascadeAllParts();
    /* Refresh from the database */
    query.dontCheckCache();
    session.executeQuery(query);
    /* Retry… */
}

Disabling forceUpdateToVersionField

The forceUpdateToVersionField configuration you apply to an object stays in effect for the lifetime of your unit of work. After you commit your transaction, forceUpdateToVersionField configuration no longer applies.

To remove forceUpdateToVersionField configuration from an object before commit time, use the unit of work method removeForceUpdateToVersionField. TopLink will not apply optimistic read locking to the object unless you change it in this transaction (that is, unless you modify its direct-to-field or aggregate object mapping attribute).