J2EE Transaction Frameworks: Distributed Transaction Primer
Pages: 1, 2, 3, 4
Serialization and isolation levels
An isolation level defines how concurrent transactions accessing a RDBMS or an EIS are isolated from one another for read purposes. The following the isolation levels are generally supported in any RDBMS or EIS. These levels are defined in the ANSI SQL92 standard in terms of three phenomena that must be prevented between concurrent transactions.
- Dirty reads: A transaction reads a row in a database table containing uncommitted changes from another transaction.
- Nonrepeatable reads: A transaction reads a row in a database table, a second transaction changes the same row and the first transaction rereads the row and gets a different value.
- Phantom reads: A transaction re-executes a query, returning a set of rows that satisfies a search condition and finds that another committed transaction has inserted additional rows that satisfy the condition.
Following are the descriptions of the isolation levels.
- TRANSACTION_READ_UNCOMMITTED: The transaction can read uncommitted data, i.e., data being changed by another transaction concurrently.
- TRANSACTION_READ_COMMITTED: This level results in the prevention of a transaction from reading uncommitted changes in other concurrent transactions. This level ensures that dirty reads are not possible.
- TRANSACTION_REPEATABLE_READ: In addition to the prevention associated with TRANSACTION_READ_COMMITTED, this level ensures that reading the same data multiple times will receive the same value even if another transaction modifies the data. Methods with this isolation level, besides having the same behavior as TRANSACTION_READ_COMMITTED, can only execute repeatable reads.
- TRANSACTION_SERIALIZABLE: The transaction has exclusive read and update privileges to data by locking it; other transactions can neither write nor read the same data. It is the most restrictive transaction isolation level and it ensures that if a query retrieves a result set based on a predicate condition and another transaction inserts data that satisfy the predicate condition, re-execution of the query will return the same result set.
| Isolation level summary | |||
| Isolation Level | Dirty Read | Non Repeatable Read | Phantom Read |
| TRANSACTION_READ_UNCOMMITTED | YES | YES | YES |
| TRANSACTION_READ_COMMITTED | NO | YES | YES |
| TRANSACTION_REPEATABLE_READ | NO | NO | YES |
| TRANSACTION_SERIALIZABLE | NO | NO | NO |
The table shown above summarizes the discussion. A lower level of isolation allows greater concurrency at the expense of more complicated logic to deal with potential data inconsistencies. A useful guideline is to use the highest isolation level provided by the RDBMS or the EIS that gives acceptable performance. Although the TX_SERIALIZABLE attribute guarantees the highest level of data integrity, it is offset by a performance trade-off because even simple reads must wait in line. All RDBMS or EIS used by a J2EE application should use the same isolation level for consistency reasons since the current J2EE specification does not define a standard way to set isolation levels when an EIS is accessed via JTA transactions. If a J2EE product does not provide a way to configure the isolation level, the RDBMS or EIS will use a default isolation level, which for most of the relational databases is TRANSACTION_READ_COMMITTED. It is strongly recommended not to change the isolation level within a transaction, especially if some work has already been done. Some enterprise information systems may even force a commit if it is attempted to change the isolation level in the middle of a transaction. They're mapped in JDBC to the static variables defined in the java.sql.Connection interface.
JTA/XA Transactions
A transaction managed and coordinated by the J2EE platform is a JTA
or XA transaction. A J2EE product is required to support JTA
transactions according to the transaction requirements defined in the
J2EE specification. There are two ways to begin a JTA transaction. A
component can begin a JTA transaction explicitly using the JTA
javax.transaction.UserTransaction interface or it can
also be started implicitly or automatically by the EJB container if an
EJB bean uses container managed transaction specification. The main
benefit of using JTA transactions is the ability to seamlessly combine
multiple application components and RDBMS/EIS accesses into one single
transaction with a little coding effort. For example, if a component X
begins a JTA transaction and invokes a method of component Y, the
transaction will be propagated transparently from component X to Y by
the platform. Enterprise beans using container-managed transaction
demarcation will not need to begin or commit transactions
programmatically as the demarcation is handled automatically by the
EJB container itself. It is always recommended to access an RDBMS or
EIS within the scope of a JTA transaction. JTA allows applications to
access transaction management independent of any specific
implementation by specifying standard Java interfaces between a
transaction manager, the transactional application, the J2EE server,
and the resource managers.
OMG Object Transaction Service
JTS specifies the
implementation of a transaction manager that supports JTA and
implements the Java mapping of the OMG Object Transaction Service
(OTS) 1.1 specification. JTS propagates transactions using IIOP. A JTS
transaction manager provides the services and management functions
required to support transaction demarcation, transactional resource
management, synchronization, and transaction context propagation. An
application component developer uses the JTA
UserTransaction interface to demarcate JTA transaction
boundaries in components. The JTS TransactionManager and
XAResource interfaces are low level APIs between a J2EE
server and enterprise information system resource managers and are not
intended to be used by applications. A J2EE platform might choose to
use a JTS implementation to support the transaction semantics defined
in J2EE specification. An example is the J2EE SDK. The JTS
implementation is transparent to J2EE components. Components should
never interact directly with JTS. Instead, they should use the JTA
UserTransaction interface for transaction
demarcation.