Friday, July 8, 2011

Theoretical background

Understanding transactions:

Following is the simple example









Explaining transactions in only four words:

ACID stands for:

AtomicTransactions are made up of one or more activities bundled together as a single unit of work. Atomicity ensures that all the operations in the transaction happen or that none of them happen. If all the activities succeed, the transaction is a success. If any of the activities fail, the entire

transaction fails and is rolled back.

ConsistentOnce a transaction ends (whether successful or not), the system is left in a state that is consistent with the business that it models. The data should not be corrupted with respect to reality.

IsolatedTransactions should allow multiple users to work with the same data, without each user’s work getting tangled up with the others. Therefore, transactions should be isolated from each other, preventing concurrent reads and writes to the same data from occurring. (Note that isolation

typically involves locking rows and/or tables in a database.)

DurableOnce the transaction has completed, the results of the transaction should be made permanent so that they will survive any sort of system crash.

Understanding Spring’s transaction management support

Spring, like EJB, provides support for both programmatic and declarative transaction management support.

Choosing between programmatic and declarative transaction management is largely a decision of fine-grained control versus convenience. When you program transactions into your code, you gain precise control over transaction boundaries,

beginning and ending them precisely where you want. Typically, you will not

require the fine-grained control offered by programmatic transactions and will

choose to declare your transactions in the context definition file.

Regardless of whether you choose to program transactions into your beans or

to declare them as aspects, you’ll be using a Spring transaction manager to interface with a platform-specific transaction implementation. Let’s see how

Spring’s transaction managers free you from dealing directly with platform specific

transaction implementations.

JDBC transactions

If you’re using straight JDBC for your application’s persistence, DataSourceTransactionManager

will handle transactional boundaries for you. To use DataSource-

TransactionManager, wire it into your application’s context definition using the

following XML:

datasource.DataSourceTransactionManager">

Notice that the dataSource property is set with a reference to a bean named

dataSource. Presumably, the dataSource bean is a javax.sql.DataSource bean

defined elsewhere in your context definition file.

Behind the scenes, DataSourceTransactionManager manages transactions by

making calls on the java.sql.Connection object retrieved from the DataSource.

For instance, a successful transaction is committed by calling the commit()

method on the connection. Likewise, a failed transaction is rolled back by calling

the rollback() method.

Hibernate transactions

If your application’s persistence is handled by Hibernate then you’ll want to use

HibernateTransactionManager. For Hibernate 2.x, it is a bean declared with the

following XML:

orm.hibernate.HibernateTransactionManager">

HibernateTransactionManager delegates responsibility for transaction management

to an org.hibernate.Transaction object that it retrieves from the

Hibernate session. When a transaction successfully completes, HibernateTransactionManager

will call the commit() method on the Transaction object. Similarly,

when a transaction fails, the rollback() method will be called on the

Transaction object.

Java Transaction API transactions

If your transactions span multiple transaction sources (e.g., two or more different databases),

you’ll need to use JtaTransactionManager:

transaction.jta.JtaTransactionManager">

value="java:/TransactionManager" />

JtaTransactionManager delegates transaction management responsibility to a

JTA implementation. JTA specifies a standard API to coordinate transactions

between an application and one or more data sources. The transactionManager-

Name property specifies a JTA transaction manager to be looked up via JNDI.

JtaTransactionManager works with javax.transaction.UserTransaction

and javax.transaction.TransactionManager objects, delegating responsibility

for transaction management to those objects. A successful transaction will be committed

with a call to the UserTransaction.commit() method. Likewise, if the

transaction fails, the UserTransaction’s rollback() method will be called.

By now, I hope you’ve found a Spring transaction manager suitable for your

application’s needs and have wired it into your Spring configuration file. Now it’s

time to put that transaction manager to work. We’ll start by employing the transaction

manager to program transactions manually.

Programming transactions in Spring

public void addRant(Rant rant) {

transactionTemplate.execute(

new TransactionCallback() {

public Object doInTransaction(TransactionStatus ts) {

try {

rant.setPostedDate(new Date());

Vehicle rantVehicle = rant.getVehicle();

Vehicle existingVehicle =

rantDao.findVehicleByPlate(rantVehicle.getState(),

rantVehicle.getPlateNumber());

if(existingVehicle != null) {

rant.setVehicle(existingVehicle);

} else {

rantDao.saveVehicle(rantVehicle);

}

rantDao.saveRant(rant);

} catch (Exception e) {

ts.setRollbackOnly();

}

return null;

}

}

}

To use the TransactionTemplate, you start by implementing the Transaction-

Callback interface. Because TransactionCallback has only one method to

implement, it is often easiest to implement it as an anonymous inner class, as

shown in listing 6.2. As for the code that needs to be transactional, place it within

the doInTransaction() method.

Calling the execute() method on the TransactionTemplate instance will execute

the code contained within the TransactionCallback instance. If your code

encounters a problem, calling setRollbackOnly() on the TransactionStatus

object will roll back the transaction. Otherwise, if the doInTransaction()

method returns successfully, the transaction will be committed.

Where does the TransactionTemplate instance come from? Good question. It

should be injected into RantServiceImpl, as follows:

class="com.roadrantz.service.RantServiceImpl">

"org.springframework.transaction.support.

TransactionTemplate">

"transactionManager"

ref="transactionManager" />

Declaring transactions

At one time not too long ago, declarative transaction management was a capability

only available in EJB containers. But now Spring offers support for declarative

transactions to POJOs. This is a significant feature of Spring because you now have

an alternative to EJB for declaring atomic operations.

Spring’s support for declarative transaction management is implemented

through Spring’s AOP framework. You can think of a Spring transaction as an aspect that “wraps” a method with transactional boundaries.

Spring provides three ways to declare transactional boundaries in the Spring

configuration. Historically, Spring has always supported declarative transactions

by proxying beans using Spring AOP. But Spring 2.0 adds two new flavors of

declarative transactions: simple XML-declared transactions and annotation-driven

transactions.

We’ll look at all of these approaches to declaring transactions later in this section,

but first let’s examine the attributes that define transactions.

Defining transaction attributes

A transaction attribute is a description of how transaction policies should be applied to a method.

Although Spring provides several mechanisms for declaring transactions, all of them rely on these five

parameters to govern how transactions policies are administered.

Propagation rules answer the question of whether a new transaction should be

started or suspended, or if a method should even be executed within a transactional

context at all.

For example, if a method is declared to be transactional with PROPAGATION_

REQUIRES_NEW behavior, it means that the transactional boundaries are the same

as the method’s own boundaries: a new transaction is started when the method

begins and the transaction ends with the method returns or throws an exception.

If the method has PROPAGATION_REQUIRED behavior, the transactional boundaries

depend on whether a transaction is already under way.

The second dimension of a declared transaction is the isolation level. An isolation

level defines how much a transaction may be impacted by the activities of other

concurrent transactions.

In a typical application, multiple transactions run concurrently, often working

with the same data to get their job done. Concurrency, while necessary, can lead

to the following problems:

Dirty read—Dirty reads occur when one transaction reads data that has been

written but not yet committed by another transaction. If the changes are

later rolled back, the data obtained by the first transaction will be invalid.

Nonrepeatable read—Nonrepeatable reads happen when a transaction performs

the same query two or more times and each time the data is different.

This is usually due to another concurrent transaction updating the data

between the queries.

Phantom reads—Phantom reads are similar to nonrepeatable reads. These

occur when a transaction (T1) reads several rows, and then a concurrent

transaction (T2) inserts rows. Upon subsequent queries, the first transaction

(T1) finds additional rows that were not there before.

In an ideal situation, transactions would be completely isolated from each other,

thus avoiding these problems. However, perfect isolation can affect performance

because it often involves locking rows (and sometimes complete tables) in the

data store. Aggressive locking can hinder concurrency, requiring transactions to

wait on each other to do their work.

Realizing that perfect isolation can impact performance and because not all

applications will require perfect isolation, sometimes it is desirable to be flexible.

Timeout: how long this transaction may run before timing out (and automatically being rolled back by the underlying transaction infrastructure).

Read-only status: a read-only transaction does not modify any data.Read-only transactions can be a useful optimization in some cases (such as when using Hibernate never flush in between).

Rollback rules

The final facet of the transaction pentagon is a set of rules that define what exceptions prompt a rollback and which ones do not. By default, transactions are rolled back only on runtime exceptions and not on checked exceptions. (This behavior is consistent with rollback behavior in EJBs.)

However, you can declare that a transaction be rolled back on specific checked exceptions as well as runtime exceptions. Likewise, you can declare that a transaction not roll back on specified exceptions, even if those exceptions are runtime exceptions.

For more detail

In my next post I will provide all practical examples of declarative transaction.

Reference: Spring in action, Manning Publisher

No comments:

Post a Comment