This tutorial requires prior knowledge of Spring Annotations and Spring Jdbc concepts. Readers are advised to go through JdbcTemplate Tutorial and Spring Annotations tutorial before proceeding.

In Spring's terminology, transaction management can be done in the following ways:

Type Definition Way of implementing
Declarative Transactions When you do something outside your business logic i.e with some simple configuration you apply a common functionality across all your code. Using @Transactional annotation
Using xml based aop configuration to have a transactional advice
Programmatic Transactions When you add code some functionality by urself so that you could control each and everything by urself. This usually mixes the unrelated functionality in your business logic. Using PlatformTransactionManager
Using TransactionTemplate

Spring Declarative transaction management


1. Annotation style transaction

To use the annotation style transaction management all you have to do is to add a 3 simple bean configuration in your xml file i.e:

  1. <context:annotation-config/>: Tells Spring framework to read @Transactional annotation
  2. <tx:annotation-driven/>: Automatically adds transaction support which eventually wraps your code in transaction scope
  3. Initializing DataSourceTransactionManager bean

Xml configuration for enabling @Transactional annotation

<context:annotation-config/>
<!-- Add this tag to enable annotations transactions -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/apu"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="userDao" class="springjdbc.transactions.declarative.annotations.AnnotatedUserDao">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>

NOTE! Dont forget to change the username and password in the above bean accordingly.

Using @Transaction in code

Following is a Dao class that uses @Transactional annotation to add declarative transactions. @Transactional at class level wraps all method in transaction scope. The @Transactional annotation has several properties like readOnly, isolation, propagation,rollbackFor, noRollbackFor etc that can be used to control how one transaction behaves and communicate with other transactions. We use readOnly property of @Transactional to mark the method eligible only for making select queries when @Transactional(readOnly=true) and update, insert queries in case @Transactional(readOnly=false). By default readOnly is false, which means you can perform all the CRUD operations, change it to true will allow only select statements to be executed. Other very useful properties of @Transactional is rollbackFor and noRollbackFor. By default Spring rolls back the transaction for exceptions of type RuntimeException or unchecked exceptions.

AnnotatedUserDao.java

/**
* @author achauhan
*/
@Transactional
public class AnnotatedUserDao implements IUserDao {
private JdbcTemplate jdbcTemplate;

public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

public void deleteUser(int uid) {
String delQuery = "delete from users where id = ?";
jdbcTemplate.update(delQuery, new Object[] { uid });

}

public int insertUser(User user) {
String inserQuery = "insert into users (username, password, enabled , id) values (?, ?, ?, ?) ";
Object[] params = new Object[] { user.getUserName(),
user.getPassword(), user.isEnabled(), user.getId() };
int[] types = new int[] { Types.VARCHAR, Types.VARCHAR, Types.BIT,
Types.INTEGER };
int number = jdbcTemplate.update(inserQuery, params, types);
return number;
}

// override the class level transactional behaviour for select method
@Transactional(readOnly = true)
public User selectUser(int uid) {
// for all the RuntimeExceptions the transactions will be automatically
// rolled back
throw new RuntimeException("A runtime exception");

}

public int updateUser(User user) throws Exception {
throw new Exception("A checked exception");
}

IMPORTANT! The above methods selectUser and updateUser are intentionally left blank so that users could understand the rollback behaviour of transactions

The selectUser method throws a RuntimeException. When Spring notices that the method is throwing a RuntimeException it automatically rolls back the transaction. Contrary to this is the call to updateUser which throws a checked exception. When spring sees that exception is checked exception, it proceeds to commit the transactions. To get a deep understanding of what Spring is doing behind the scenes, you can switch the log4j level to trace and check out the console.

Overriding default rollback behaviour

To override the default rollback behaviour, we use the rollbackFor and noRollbackFor properties of @Transactional. So taking the example of selectUser method which throws a RuntimeException. To tell the Spring that it should not roll back the transaction in this case, we will write :
@Transactional(readOnly = true,noRollbackFor=RuntimeException.class)
Now if you call the selectUser method, following trace is seen on console.

Following is the comparison of console output with default rollback setting and with overriden rollback setting for selectUser method call.

@Transactional(readOnly = true)

20:57:29,141 TRACE [TransactionInterceptor] Getting transaction for [springjdbc.IUserDao.selectUser]
20:57:29,142 TRACE [TransactionInterceptor] Completing transaction for [springjdbc.IUserDao.selectUser] after exception: java.lang.RuntimeException: A runtime exception
20:57:29,142 TRACE [RuleBasedTransactionAttribute] Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: A runtime exception
20:57:29,142 TRACE [RuleBasedTransactionAttribute] Winning rollback rule is: null
20:57:29,142 TRACE [RuleBasedTransactionAttribute] No relevant rollback rule found: applying default rules
20:57:29,142 DEBUG [DataSourceTransactionManager] Initiating transaction rollback

@Transactional(readOnly = true,noRollbackFor=RuntimeException.class)

21:25:07,694 TRACE [TransactionInterceptor] Getting transaction for [springjdbc.IUserDao.selectUser]
21:25:07,695 TRACE [TransactionInterceptor] Completing transaction for [springjdbc.IUserDao.selectUser] after exception: java.lang.RuntimeException: A runtime exception
21:25:07,695 TRACE [RuleBasedTransactionAttribute] Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: A runtime exception
21:25:07,696 TRACE [RuleBasedTransactionAttribute] Winning rollback rule is: NoRollbackRuleAttribute with pattern [java.lang.RuntimeException]
21:25:07,697 DEBUG [DataSourceTransactionManager] Initiating transaction commit

Our test class is similar to the one we used in JdbcTemplate tutorial.

2. Xml based Transaction configuration

To use the Xml based Spring Transaction management all you have to do is to add 3 simple bean configuration in your xml file i.e:

  1. Initializing DataSourceTransactionManager bean
  2. <tx:advice />: Configures the transaction advice. In this advice we configure various transaction properties for different methods. So what was earlier written as @Transactional(readOnly = true) will now be written as <tx:method name="select*" read-only="true" />.
  3. <aop:config/>: Final step is to apply the transaction advice using aop configuration.

<context:annotation-config/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="select*" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="userDaoTxPointcut" expression="execution(* springjdbc.IUserDao.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="userDaoTxPointcut" />
</aop:config>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/apu"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="userDao" class="springjdbc.transactions.declarative.xml.UserDao">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>

The dao class will be same as the AnnotatedUserDao we have seen above but without Spring @Transactional annotation.

Programmatic Transactions

Download Source