Welcome!

Open Source Authors: Maureen O'Gara, Jeremy Geelan, Liz McMillan, Reuven Cohen, Lavenya Dilip

Related Topics: Open Source, Java

Open Source: Article

Bringing Advanced Transaction Capabilities to Spring Applications

Inversion of control and dependency injection

Dirty reads occur when data that has been updated in a transaction - and not yet committed - is read by another transaction. If an asset report is being run while a stock is being purchased and before the purchase (transaction) has committed, the asset report may get a dirty read. For example, if the read came after the debit but before the credit, the result could be a report that doesn't balance

Non-repeatable reads occur when a transaction reads data, a second transaction subsequently updates that data, and the first transaction reads the data again after the second transaction's update. If an asset report is being run while a bank account balance is being updated and the value of the bank account is queried twice during the report for some reason, the bank account values reported may be inaccurate and inconsistent.

Phantom reads occur when a transaction reads a range of data (rows), a second transaction subsequently deletes or inserts data (a row) in this range, and the first transaction reads the range of data again after the second transaction's delete or insert. If an asset report is being run while a new stock is being purchased (inserted) and the stock purchased detail is queried twice during the report for some reason, the report may be inaccurate. As such, the stock portfolio may be reported inconsistently.

The read issues described may or may not be a concern for an application. Whether it's a problem or not depends entirely on the business context. For example, if the report is being used for public reporting or in an asset management decision system, the inconsistencies will be unacceptable. However, if used for ad hoc real-time reporting or in some situation where inconsistencies are unlikely, the possible inconsistency may be tolerable. There are also resource and performance costs involved that must be considered in the design of the system. Isolation levels can be used to prevent or allow these situations.

The most common use of isolation levels is when accessing a database. Different vendors have proprietary isolation levels, locking mechanisms, and other behaviors that are well beyond the scope of this article and so we'll briefly explain the standard isolation levels defined only in the JDBC API. Note that this list is provided in order of the weakest to strongest isolation with an inverse correlation as far as performance is concerned.
•  TRANSACTION_NONE: transactions are not supported.
•  TRANSACTION_READ_UNCOMMITTED: dirty reads, non-repeatable reads, and phantom reads can occur.
•  TRANSACTION_READ_COMMITTED: dirty reads are prevented; non-repeatable reads and phantom reads can occur.
•  TRANSACTION_REPEATABLE_READ: reads and non-repeatable reads are prevented; phantom reads can occur.
•  TRANSACTION_SERIALIZABLE: dirty reads, non-repeatable reads, and phantom reads are prevented.

Local Transactions and JTA Global Transactions
The complexity of a transaction increases with the number of resources the application enlists in the transaction.

A local transaction involves only one resource and the transaction activity is scoped and coordinated locally to the resource itself.

A global transaction may enlist more than one resource manager including multiple databases, message systems, and legacy mainframe systems. To achieve atomic outcomes in the global transaction, coordination between a transaction manager and these resources is required. This coordination is achieved via the distributed transaction protocol defined in the DTP and XA specifications published by the Open Group.

The following diagram is a DTP model that illustrates the relationship and interaction between the application, resource managers, and the transaction manager. (Figure 1)

Applications communicate with the transaction manager to begin and end transactions and enlist resources. When the application requests that a transaction be committed, the transaction manager - such as Oracle Application Server, BEA WebLogic, or IBM WebSphere - coordinates the two-phase commit protocol. The transaction manager mediates between applications and resource managers to delineate the boundaries of units of work. It also performs a termination protocol that communicates the outcome of the transaction to all participants. A component can begin a JTA transaction programmatically using the UserTransaction interface or it can be started by the EJB container as specified in the transaction-attributes of the EJB's deployment descriptor.

Why Spring with JTA TransactionManager
The transactioning requirements for most applications are met by either a Spring transaction management strategy or a JTA transaction manager in the middle tier. On occasion, applications must support remote calls in which a transaction context is propagated over multiple processes. In this case, using the facilities inherent in the EJB distributed-component model with container-managed JTA transactioning support is appropriate. If you're looking for a J2EE framework that provides declarative transaction management and a flexible persistence engine, Spring is a great choice. It lets you choose the features you want without the added complexities of EJB.

Like J2EE, Spring provides support for programmatic transaction demarcation. However, a more dynamic application design comes from the use of demarcation specified either by annotation or AOP. These two techniques are illustrated in the example provided; complete details can be found in the Spring documentation.

Another unique and clever Spring feature is the ability to switch from using a local transaction manager - such as a database datasource - to a JTA transaction manager. This can be done simply by manipulating a few lines of configuration and using a different PlatformTransactionManager implementation. Migration of this nature - that is the need to add another resource within the scope of a transaction previously designed for only resource local transactional work - is common in the extended lifecycle of an application. However, it's dangerously error-prone in conventional J2EE applications. Note that the datasource being used in this scenario must be one that has a contract with the JTA implementation being used to provide enlistment in the global transaction. This is generally the case if the (XA) datasource is obtained from the application server using JNDI. This is shown in the example provided by using Spring's JndiObjectFactoryBean that frees the application code from JNDI dependency.

Most enterprise applications such as high-end financial applications and highly available telecom systems require comprehensive transactional support. By using Spring in tandem with an enterprise JTA implementation, powerful, and generally proprietary, quality of service features - such as high-availability, clustering and grid support, fail-over, peer recovery, non-stop transactioning, integration, interoperability (such as OTS and WS-TX), monitoring and administration, and other features present in enterprise JTA implementations and application server environments - can be exploited while the application itself retains all of the benefits of Spring previously described.

Two examples in which Spring has provided support and integration beyond standard JTA are transaction names and per-transaction isolation levels. Due to the complex nature of transactions - in particular global transactions where a number of systems are involved in a single activity - it becomes critical to have meaningful information for administration, monitoring, and debugging. Named transactions provide a way of identifying and grouping transactions by a type. Spring provides the name of the class and method that initiated the transaction as this transaction name identifier. This is very useful, particularly when imported into a transactioning system that can then correlate this information with other data. Suddenly, the enterprise system has a debuggable holistically monitored transactional business process rather than a cryptic log of Xid byte arrays.

As discussed in the section on isolation levels, it becomes apparent that a number of factors including performance, strict versus relaxed ACID requirements, data representation and usage, and even vendor implementation behaviors dictate that different isolation levels must be used for different cases. This leads to the need for fine-grained control of isolation levels, particularly when connection-related resources are at a premium. Again, this is a case in which littering application code with common API calls - such as setting and resetting transaction isolation levels - is not ideal. Instead, Spring presents a dynamic solution by exposing the per-transaction isolation-level features present in some extended JTA implementations. Spring provides this in exactly the same fashion as transaction demarcation in which demarcation is specified as a "propagation" attribute and the isolation level is specified as an "isolation" attribute. These settings are described in detail in the example application as well as in Spring documentation.


More Stories By Frances Zhao

Frances Zhao is a principal product manager in the Oracle Fusion Middleware team. Her focus is on the core J2EE container.

More Stories By Paul Parkinson

Paul Parkinson has been working with and developing transaction processing technology for 15 years. His work at Oracle includes the development of the Java Transaction API and Java Transaction Service implementations in the OC4J application server as well as performance and high-availability features, Web Service Transactions, and transactional aspects of JCA.

Comments (2) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
Guy Pardon 07/24/07 08:58:32 AM EDT

(Trying again - link not property showing in my first post)

A complete working JMS/JDBC application with Spring JTA integration can be found here:

http://www.onjava.com/pub/a/onjava/2006/02/08/j2ee-without-application-s...

Guy Pardon 07/24/07 08:56:16 AM EDT

Nice article, though the sample application seems a bit exotic (2 databases are being combined in a synchronous, tighly-coupled integration scenario). More common is a loosely-coupled architecture where you have one (JMS) queue and one database - banks are also more likely to work that way.

A complete working JMS/JDBC application with Spring JTA integration can be found here:

www.onjava.com/pub/a/onjava/2006/02/08/j2ee-without-application-server.html

more (and in-depth) info on Spring's transaction configuration options is in following presentation:

http://media.techtarget.com/tss/BeJUG/J2EEAppsSpring/player.html

Disclaimer: I should mention that I am the author of both these publications, and heavily involved in some of the related technologies.

Best
Guy