Implementing Transaction Locking in Code

A multi-user application must control concurrency, the simultaneous access of the same data by many users. Otherwise, data could be updated or changed improperly. Concurrency control is managed through the Transaction interface. This topic describes how transactions fulfill the following important requirements of an information management system:

Transactions use locks to control concurrent access to data, achieving two important database goals:

The Business Components for Java framework supports a locking model that provides the following features and benefits:

Using the Business Components for Java framework, you can request locks on rows in entity objects or view objects. Locking an entity object row places a database lock on that row. When locking a view object's row, the framework requests locks on those Entity rows that are used in the view object's row.

Business Components for Java supports the locking styles listed in the table below. Each style represents a trade-off between scalability, performance, and consistency of data. For example, placing database locks early (pessimistic locking) reduces scalability but decreases the likelihood of data inconsistencies. When you change the locking style, the change only affects subsequent locks. Locks already in place do not change.

Locking Style

Comments

Pessimistic Locking

Locks are automatically placed upon the underlying row immediately before the first client change is made. This is the default style for Application Modules. Represented by the constant Transaction.LOCK_PESSIMISTIC.

Optimistic Locking

Locks are automatically placed upon the underlying row during the "save to database" logic. Represented by the constant Transaction.LOCK_OPTIMISTIC.

Explicit Locking

Locks are manually placed, at the correct point in time, by explicit calls from the client. If no lock calls occur, then only the database locks, obtained when the rows are flushed to the server, are obtained. Represented by the constant Transaction.LOCK_NONE.

The following code example demonstrates pessimistic locking mode:

 if ( myEntity.getPostState() != Entity.STATUS_NEW
&& myEntity.getDBTransaction().getLockingMode()
== Transaction.LOCK_PESSIMISTIC
&& !myEntity.isLocked() )
{
myEntity.lock();
}
return myEntity;

About Lock Failure

Locks may fail for any of the following reasons:

In each case, a different type of error is raised to indicate the problem. This permits higher level callers to indicate the error in question, and potentially retry the operation.

Releasing Locks

After a lock is placed on a given object, it is added to the list of Transaction participants. After the Transaction performs a commit or rollback operation, each Transaction participant is notified of the outcome of the operation. Each object is given an opportunity to release any internal state, such as lock indicator flags, that it may hold during this notification cycle.

About Low-level Locking

Independent of the locking style selected, the low-level APIs permit the explicit locking of View/Entity Rows by calling their lock method at the appropriate time.

After the initial lock call for a given row object, subsequent calls are ignored unless the corresponding database transaction has had the commit or rollback operation performed, because locks are automatically released at these times.

The call to place a lock can fail for a number of reasons:

In each case, an exception is thrown to indicate that a problem occurred. These exceptions can also occur at other times, such as changing the value of a column, because locks can be placed implicitly at that time.

An Entity Row provides a method for testing the locked status, as follows:

/** 
* Is the Row locked? 
**/ 
public boolean isLocked()