Chapter 5. EJB transactions

Build EJBs which satisfy transactional requirements

EJB transactions are a set of concepts and a set of mechanisms that attempt to insure the integrity and consistency of a database for which multiple clients may attempt to access it and/or update it simultaneously.

An Entity EJB is a representation of business data. Its state is represented completely by the values of its persistent instance variables, that is, those that are synchronized with the persistent store (database). If a transactional operation in such an Entity EJB fails, then the system considers it to have been successfully rolled back if its underlying business data is put back to its pre-transactional state. Instance variables that do not represet data in the persistent store cannot be restored. If the EJB has container-managed persistence, then all the synchronization of the variables with the persistent store will be automatic, even after a rollback. This takes some work away from the developer, but it does imply that the EJB must be no more than an object representing a database row.

Because of the assumption above, transaction management in Entity EJBs should never be under programmer control. The EJB 2.0 specification prohibits an Entity EJB from managing its own transactions; the container must do everything. Therefore, if your transaction management requirements are beyond those offered by the container, then you can't use Entity EJBs at all. Of course, the EJB paradigm says that an Entity EJB is simply a model of business data and, as such, will never need a more complicated transaction mechanism than that offered by the container.

Where Entity EJBs are involved in a transaction, the Entity EJBs' methods will normally be called by a method in a Session EJB.

Transactions can be managed by the container; in this case the developer's role is to specify the correct declarative transaction attributes in the deployment descriptor. Only very limited programmatic control of transactions is allowed. Entity EJBs MUST use this mechanism. Alternatively, a Session EJB can opt to manage its own transactions programatically. Because a Session EJB s not just a model of business data, the container can only offer limited support for transaction management, as will be discussed. This means that if the Session EJB has a state that will change during a transaction (e.g., instance variables will change value), then the developer has to provide support for this, even in container-managed transactions. The EJB API provides the SessionSynchronization interface for this.

Basic properties of transactions can be summarized using the ACID mnemonic:

  • Atomic

    All or nothing. If a transaction is interrupted, all previous steps within that transaction are undone.

  • Consistent

    The state of objects and/or the state of tables within a database move from one consistent state to another consistent state.

  • Isolated

    What happens within one transaction should not affect or be visible within another transaction.

  • Durable

    The effects of a transaction are persistent.

Local and global transactions

Local transactions – All operations are carried out on a same database.

All modern database engines can handle transactions access to their own data stores. A local transaction is exactly that: it is confined to a single process executing against a single database server.

Distributed transactions – Operations are carried out with multiple servers, two-phase commit protocol is used, need "transaction manager" for coordinating two-phase commit protocol.

However, in more sophisticated systems a transaction may encompass multiple database servers, perhaps from different vendors and with different protocols. A transaction that can handle multiple databases is called a global (or distributed) transaction; if the servers are different (in vendor, or protocol) this is called a heterogenous global transaction.

A single database server cannot handle global transactions; neither is there direct support in the JDBC specification, because it operates at the level of an individual database connection. Generally we need a transaction manager to control global transactions. The Java Transaction API (JTA) provides access to the services offered by a transaction manager. If EJBs require control of global transactions, they can get access to JTA via the container.

Transaction Attributes

Transactions can be defined at several different levels and in several different ways.

  • Levels.

    With respect to levels, transaction attributes may be defined at the level of EJB (or class), method within class, or segment of code within method. The more specific specification take precedence over the specification for the containing segment. Thus, attributes specified for a particular method take precedence over the specification for an entire EJB.

  • Specification.

    With respect to specification, transaction attributes may be specified through deployment descriptors or through Java code embedded in a class. Unless the programmer is skilled in working with transaction and unless there is a compelling reason to do so, a best practices approach for most applications will be to specify transactions declaratively - through deployment descriptors attached to EJB classes that enable the EJB Container to generate and handle transactions. Declarative transactions attributes can be set at the time of development, through WebSphere Studio, and/or at the time of deployment (or thereafter), through the WebSphere Administrative Console. In both cases, attributes can be set for the bean as a whole, for individual methods, or both.

The EJB 2.0 Specification (see Chapter 17) includes six defined transaction attributes:

Table 5.1. Transaction Attributes

AttributeDescription
TX_REQUIRED Methods executed within a transaction. If client provides transaction, it is used; if not, new transaction generated. Commit at end of method. Default attribute set by WebSphere Studio. Well-suited for EJB Sessions.
TX_MANDATORY Client of this EJB must create a transaction in which this method operates, otherwise an error. Well-suited for EJB Entitys.
TX_REQUIRES_NEW Methods executed within a transaction. If client provides transaction, it is suspended. A new transaction is generated, regardless. Commit at end of method.
TX_SUPPORTSTransactions optional.
TX_NOT_SUPPORTEDTransactions not supported; if provided, ignored.
TX_BEAN_MANAGEDCode in the EJB responsible for explicit transaction control. Applicable in WebSphere to EJB Sessions only.

Isolation Levels

Isolation levels provide a degree of control of the effects one transaction can have on another. Since concurrent effects are determined by the precise ways a DBMS handles locks, and databases and their drivers handle these locks differently, the semantics of isolation mechanisms based on them are not well-defined. Nevertheless, certain defined or approximate properties can be specified.

The following transaction isolation levels are defined for Session and Entity Beans:

Table 5.2. Isolation Levels

Isolation LevelDescription
TRANSACTION_SERIALIZABLE

Strongest level of isolation. All rows locked for duration of transaction. Can produce deadlocks! (But not if Find for Update set to false.)

A transaction ensures that no other transaction can read or write to the data it accesses. Dirty reads, nonrepeatable reads and phantom reads are not possible.

TRANSACTION_REPEATABLE_READ

Transaction always reads same data during transaction. Phantom records possible. Default level of isolation set by WebSphere Studio. Usually suitable for all but most critical operations.

Once a transaction has read a set of data, repeated reads of the same data return the same values, even if other transactions have subsequently modified the data. Dirty reads and nonrepeatable reads are not possible, but phantom reads are.

TRANSACTION_READ_COMMITTED

Can not read uncommitted data by another transaction, but nonrepeatable reads and phantom records possible.

A transaction is not allowed to read uncommitted data. Dirty reads are not possible, but nonrepeatable reads and phantom reads are.

TRANSACTION_READ_UNCOMMITTED

Can read uncommitted data by another transaction, and nonrepeatable reads and phantom records possible.

A transaction may read any data currently on a data page, regardless of whether or not the data has been committed. Dirty reads, nonrepeatable reads, and phantom reads are possible.

Transactions are supposed to be atomic, that is, everything succeeds or everything fails together. However, database engines generally allow many simultaneous connections to be reading and updating data simultaneously. Thus it is very possible for one connection to read or update data that another connection is in the process of reading or updating. Where this simulataneous access is permitted, the following types of error can occur:

Table 5.3. Types of error

ErrorDescription
Dirty reads

A transaction reads data written by another transaction that has not been committed yet. Because this data is uncommitted, a transaction failure would roll back these read changes.

Occurs when one transaction (T2) reads data that has been modified by previously started transaction (T1), but not committed

What happens if the T1 rolls back? T1 has incorrect data, thus "dirty read".

Nonrepeatable reads

A transaction rereads data it has previously read and finds that data has been modified by another committed transaction in the meantime.

Occurs when one transaction (T1) reads same data twice, while another transaction (T2) modifies the data between the two reads by T1.

T1 gets different value between the first and the second read, thus "nonrepeatable read".

Phantom reads

A transaction reexecutes a query returning a set of rows that satisfy a search condition and finds that the set of rows satisfying the condition has changed due to another committed transaction in the meantime.

Occurs when one transaction begins reading data and another inserts to or deletes data from the table being read.

Adding an isolation level

You can use the deployment descriptor editor to add an isolation level to an EJB 2.0 CMP entity bean.

To add an isolation level to an EJB 2.0 entity bean with container-managed persistence:

  1. Switch to the J2EE Perspective.

  2. In the J2EE Hierarchy view, select the desired EJB JAR file (titan).

  3. Select Open With > Deployment Descriptor Editor from the pop-up menu.

  4. On the Access page of the editor, scroll to the Isolation level section.

  5. Click Add. The Add Isolation Level wizard appears.

  6. Select a type of isolation level from the following choices:

    Isolation level

    • Repeatable read - This isolation level prohibits dirty reads and nonrepeatable reads, but it allows phantom reads.

    • Read committed - This isolation level prohibits dirty reads, but allows nonrepeatable reads and phantom reads.

    • Read uncommitted - This isolation level allows reading uncommitted changes (data changed by a different transaction that is still in progress). It also allows dirty reads, nonrepeatable reads, and phantom reads.

    • Serializable -This isolation level prohibits the following types of reads:

      1) Dirty reads, in which a transaction reads a database row containing uncommitted changes from a second transaction,

      2) Nonrepeatable reads, in which one transaction reads a row, a second transaction changes the same row, and the first transaction rereads the row and gets a different value, and

      3) Phantom reads, in which one transaction reads all rows that satisfy an SQL WHERE condition, a second transaction inserts a row that also satisfies the WHERE condition, and the first transaction applies the same WHERE condition and gets the row inserted by the second transaction.

  7. Click Next.

  8. Select one or more enterprise beans from the list of beans found, then click Next. The enterprise beans selected here are the ones whose methods you want to assign to the isolation level.

  9. Select one or more of the method elements from the list.

  10. Click Finish.

The isolation level is added. To remove the isolation level, select it and click the Remove button.

Implementing Two-Phase Commits

Operations that involve two different EJBs present special problems for transaction processing. For example, an update to the first EJB may be successful, but the update to the second one may fail. To ensure that the database is left in a consistent state, the update to the first EJB, and hence its corresponding table in the DB, must be undone, or rolled back.

Roll back is an operation that requires a special form of transaction support, called two-phase commit. Transactions that are managed by the container are defined with respect to the thread in which the operations that are to be subjected to two-phase commit take place. Thus, if the architecture includes a Session EJB in which a method calls a domain object that, in turn, carries out operations on several entity EJBs that are to be treated as an atomic unit, then the transaction should be defined in the Session EJB method.

A checklist of key steps for specifying this follows:

  1. In the Session EJB method, enclose the statement(s) that start the thread that eventually reaches the operations on multiple EJBs within a try-catch block; e.g.:

    try  {
    	return domain.updateBoth(dataBean1, dataBean2);
    }  catch ( Exception e )  {
    	mySessionCtx.setRollbackOnly();
    }
    								

  2. In the Server Perspective, select or create the particular server in which you wish to carry out two-phase commit and open its deployment descriptor (.wsi file). Select the DataSource tab and under Server Settings, go to the JDBC Prover List. There, designate Add... and select IBM DB2 as the Database Type and DB2 Universal JDBC Provider (XA) as the JDBC Provider type. Note: XA is the designation for two-phase commit resources. When prompted, give the new two-phase resource a name.

    DB2 Universal JDBC Provider (XA)

  3. Select the newly created resource and add a new DataSource, in the next panel down. If you are adding two-phase commit late in the process after you have defined a server with single-phase commit, you may wish to use the same JNDI name so that you don't have to change the JNDI name on individual EJBs.

Isolation levels in EJB transactions

A database engine will provide isolation of transactions, that is, transactions are prevented from interacting with one another and giving rise to the error described above. However, complete isolation of transactions, although offering the greatest assurance of data integrity, is potentially a performance bottleneck and may not be required. An EJB that is starting a transaction may therefore, in some circumstances, request a particular level of isolation. The levels that are available are shown below.

Table 5.4. Isolation levels in EJB transactions

Isolation levelDirty reads may occurNonrepeatable reads may occurPhantom reads may occur
TRANSACTION_READ_UNCOMMITTED (no isolation)YesYesYes
TRANSACTION_READ_COMMITTED (partial isolation)NoYesYes
TRANSACTION_REPEATABLE_READ (partial isolation)NoNoYes
TRANSACTION_SERIALIZABLE (full isolation)NoNoNo

With Entity EJBs that use container-managed persistence (CMP), the developer has NO control over the isolation level provided for transactions. This is because the synchronization of the data with the persistent store is handled entirely by the container. In all other cases, the EJB may set the isolation level.

Professional hosting     Belorussian informational portal         Free SCBCD 1.3 Study Guide     Free SCDJWS 1.4 Study Guide     SCDJWS 1.4 Quiz     Free IBM Certified Associate Developer Study Guide     Free SCJP 5.0 (Tiger) Study Guide     Free Mock Exam Engine     Free SCWCD 1.4 Study Guide


webhosting provided by ixvar inc