Transaction Services with JTA and JTS
Transaction Services Overview
Guaranteeing that your enterprise applications employ transactions and adhere to ACID principles can require a lot of hand-coding overhead. It is true that you could conceivably identify every scenario in your system in which a collection of operations must occur within a transaction and subsequently write code to commit or rollback depending on the outcome of processing. For a few simple transactional scenarios, this may be a reasonable approach. However, for even moderately more complex applications, the number of transaction scenarios and number of operations per transaction scenario add a significant burden to your set of programming tasks and keep you from focusing on application logic.
Furthermore, the large-scale distribution of both application and state in an enterprise system mandates a need for sophisticated distributed transaction management services. The heterogeneity of platforms on which these applications run can further complicate matters as you strive to implement a standard distributed transaction processing methodology. As we saw in Chapter 2, standards such as the X/Open Distributed Transaction Processing Model (as shown in Figure 2.2) provide a common framework within which transactions may operate in a heterogeneous distributed environment. The standard propagation of transaction context information between distributed applications enables a standard mechanism within which distributed transaction applications may operate.
Declarative programming of transactions involves defining transaction attributes for components or their individual operations. The container then manages transactional processing for the component by using an underlying transaction service. J2EE enables the declaration of transactional attributes for application components such as Enterprise JavaBeans (EJB). These are the latest standard transaction attribute classifications defined by the J2EE, with older EJB standard style analogues shown in parentheses:
Required (TX_REQUIRED): The component is required to operate inside of a transaction. If the calling client provides a transaction context within which the component operation is invoked, that transaction context is used. Otherwise, the container environment will provide a new transaction context within which the operation runs and will then attempt to commit the transaction when the operation completes.
RequiresNew (TX_REQUIRES_NEW): The container creates a new transaction when the component is invoked and attempts to commit the transaction when the operation completes. Any transactions that were propagated by the calling client will be suspended and then resumed when the operation completes.
NotSupported (TX_NOT_SUPPORTED): The container will not support the operation of a component within a transaction context. Any transaction context that was propagated by the calling client will be suspended and then resumed when the operation completes.
Never (some TX_BEAN_MANAGED similarities): The container requires that the client does not propagate a transaction context for use with the invoked component operation. Otherwise, an exception will be thrown. In such cases, the component may manage its own transaction programmatically.
Supports (TX_SUPPORTS): The container itself will not create any new transaction context within which the component may operate. However, any transaction context that was propagated by the calling context can be used with the called component. That is, the operation of the component will process within the context of the propagated transaction.
Mandatory (TX_MANDATORY): The container requires that the client propagate a transaction context for use with the invoked component operation. Otherwise, an exception will be thrown.
Transaction Isolation Levels
Transaction services also allow for the specification of isolation levels. The isolation level defines how and when changes made to data within a transaction are visible to other applications accessing that data. Isolation levels range from rigidly restricting visibility of changes to not limiting visibility of changes at all. We defined and introduced the concept of isolation levels in Chapter 6 in the context of JDBC updates to databases. However, because isolation levels can also apply to concurrent transactions involving general back-end enterprise information systems (EISs) and messaging services, we redefine transaction isolation levels here to incorporate the broader definition of transactions:
TRANSACTION_NONE: Transactions are not supported at all when identified by this isolation level.
TRANSACTION_READ_UNCOMMITTED: This level allows other transactions to see state changes made by this transaction before a commit has been issued.
TRANSACTION_READ_COMMITTED: This level does not allow other transactions to see state changes made by this transaction until a commit has been issued (that is, does not allow "dirty reads"). Also sometimes referred to as ReadCommitted.
TRANSACTION_REPEATABLE_READ: In addition to TRANSACTION_READ_ COMMITTED level support, this level also does not allow a transaction to read data more than once and observe different data values because some other transaction made state changes to that data in the meantime (that is, does not allow "nonrepeatable reads" or "dirty reads"). Also sometimes referred to as RepeatableRead.
TRANSACTION_SERIALIZABLE: In addition to TRANSACTION_REPEATABLE_READ level support, this level does not allow a transaction to read a collection of data more than once and as constrained by a particular predicate condition. It also does not allow a transaction to observe newly added data because some other transaction added data satisfying the same predicate condition in the meantime (that is, does not allow "phantom reads," "nonrepeatable reads," or "dirty reads"). Also sometimes referred to as Serializable.
Transaction services can also support different models for encapsulating operations in a transaction. Simple transactions need to simply define the beginning of a transaction at some stage of processing and then conclude with either committing or aborting (that is, rolling back) the transaction. More complicated models of transaction processing also exist, however. The primary models for transaction processing are illustrated in Figures 14.8 through 14.10.
The flat transaction model depicted in Figure 14.8 relies on simple begin, commit, and abort functionality of a transaction service. A transaction context is created by a transaction service and encapsulates all operations until the transaction is committed or aborted.
The flat transaction model.
The chained transaction model depicted in Figure 14.9 allows for one to persistently save a portion of the work accomplished up until a certain point. Rollback to the beginning of the chained transaction is allowed if the chained transaction follows the "saga model."
The chained transaction model.
The nested transaction model depicted in Figure 14.10 allows transactions to be nested within other transactions. A nested subtransaction can be committed or aborted individually. Thus, complex transactions can be decomposed into more manageable subtransactions. Subtransactions can commit or rollback without requiring the entire transaction to commit or rollback.
The nested transaction model.
X/Open Distributed Transaction Processing Standard
Chapter 2 described the standard X/Open Distributed Transaction Processing (DTP) model utilized by the Java transactions architecture for providing a standard distributed transaction processing framework (see Figure 2.2). An X/Open resource manager (RM) is used to describe a management process for any shared resource but is most often used to mean a DBMS. The X/Open transaction manager (TM) is the module responsible for coordinating transactions among the various distributed entities. A TX interface between application programs and TMs enables applications to initiate the begin, commit, and rollback of transactions, as well as to obtain the status of transactions. RMs participate in distributed transactions by implementing a transaction resource interface (XA) to communicate information needed by TMs for coordinating transactions.
TMs are often configured to manage a particular domain of distributed RMs and applications. Communication resource managers (CRMs) provide a standard means for connecting distributed transaction managers to propagate transaction information between different transaction domains for more widely distributed transactions. The standard interface between TMs and CRMs is defined by an XA+ interface, whereas communication resource manager to application program interfaces are defined by three interfaces known as TxRPC, XATMI, and CPI-C.
Two-Phase Commit Protocol
A TM can guarantee that all steps in a distributed transaction are atomically completed using information from the distributed RMs. A TM accomplishes this using a two-phase commit protocol. The two-phase commit protocol helps guarantee ACID principles by ensuring that all RMs commit to transaction completion or rollback to an original state in the event of a failure. These are the two-phase commit protocol steps:
Phase OneCommit Preparation: A prepare for commit message is first sent to each resource manager (for example, DBMS) with updated data involved in a transaction. Each resource manager then persists a description of the updates it has made within the context of the current transaction. Resource managers can also opt to abort the transaction at this stage, and then the whole transaction can be aborted by the transaction manager.
Phase TwoActual Commit: If the transaction was not aborted, the transaction manager will send a commit message to all resource managers involved in the transaction. The resource managers will then commit their updates.
Object Transaction Service
The CORBAservice known as the Object Transaction Service (http://www.omg.org/cgi-bin/doc?formal/00-06-28) defines interfaces to implement transactional behavior for distributed CORBA objects. Distributed CORBA objects can participate in transaction via an ORB and the OTS. The OTS supports both flat and nested transactions. Because OTS relies on the X/Open DTP standard, nonCORBA-based applications can also interoperate with OTS. OTS is defined primarily in the org::omg::CosTransactions module, but an auxiliary org::omg::CosTSPortability module also defines two interfaces defined for portable transaction context propagation.
OTS currently represents perhaps the only CORBAservice that has been wholeheartedly adopted by the J2EE distributed computing services paradigm. As you'll see later in the chapter, the Java Transaction Service (JTS) is simply a Java mapping of the OTS. At the time of this writing, the OTS and JTS were not required by J2EE vendors to be implemented as a means for providing transactional interoperability between J2EE servers. However, the J2EE specifications do recommend that J2EE vendors support OTS and JTS for more greater interoperability and suggest that such support may be mandatory in a future specification.
Core OTS Types
As with other CORBA specifications, the OTS depends on a set of fundamental types. Two IDL enum types and three IDL struct types define the most important types defined in the CosTransactions IDL module. The Java mapping for these types is depicted in Figure 14.11. The five types of interest are listed here:
Status: Status is an IDL enum that identifies the various states of a transaction.
Vote: Vote is an IDL enum that identifies the responses from resource managers after the commit preparation phase (Phase One) of a two-phase commit protocol.
otid_t: otid_t is an IDL struct that is a transaction identifier. It is based on the X/Open notion of a transaction ID referred to as XID.
TransIdentity: TransIdentity is an IDL struct that encapsulates a handle to a transaction. A TransIdentity has an otid_t transaction identifier as well as a handle to its transaction coordinator and terminator.
PropagationContext: PropagationContext is an IDL struct that encapsulates transaction context information to be propagated between distributed entities involved in a transaction. A transaction timeout and current transaction identity are part of the context. A sequence of parent transaction identities in a nested transaction can also be included. Implementation-specific data can also be added to a propagation context.
Basic OTS types.
Page 2 of 4