Wednesday, November 4, 2015

Spring - Declarative transaction Management using Spring AOP



What is the difference between concern and cross-cutting concern in Spring AOP?
Concern is behavior which we want to have in a module of an application. Concern may be defined as a functionality we want to implement to solve a specific business problem. E.g. in any eCommerce application different concerns (or modules) may be inventory management, shipping management, user management etc.
Cross-cutting concern is a concern which is applicable throughout the application (or more than one module). e.g. logging , security and data transfer are the concerns which are needed in almost every module of an application, hence they are termed as cross-cutting concerns.

What are the available AOP implementations?
Main java based AOP implementations are listed below :
  1. AspectJ
  2. Spring AOP
  3. JBoss AOP
You can find the big list of AOP implementations in wiki page.
What are the different advice types in spring?
An advice is the implementation of cross-cutting concern which you are interested in applying on other modules of your application. Advices are of mainly 5 types :
  1. Before advice : Advice that executes before a join point, but which does not have the ability to prevent execution flow proceeding to the join point (unless it throws an exception). To use this advice, use @Before annotation.
  2. After returning advice : Advice to be executed after a join point completes normally. For example, if a method returns without throwing an exception. To use this advice, use @AfterReturning annotation.
  3. After throwing advice : Advice to be executed if a method exits by throwing an exception. To use this advice, use @AfterThrowing annotation.
  4. After advice : Advice to be executed regardless of the means by which a join point exits (normal or exceptional return). To use this advice, use @After annotation.
  5. Around advice : Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. To use this advice, use @Around annotation.

What is Joint point and Point cut?
Join point is a point of execution of the program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution. For example, all the methods defined inside your EmployeeManager interface cab be considered joint points if you apply any cross-cutting concern of them.
Pointcut is a predicate or expression that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, expression “execution(* EmployeeManager.getEmployeeById(..))” to match getEmployeeById() the method in EmployeeManager interface). The concept of join points as matched by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut expression language by default.

There are 7 types of propagation supported by Spring :
  • PROPAGATION_REQUIRED – Support a current transaction; create a new one if none exists.
  • PROPAGATION_SUPPORTS – Support a current transaction; execute non-transactionally if none exists.
  • PROPAGATION_MANDATORY – Support a current transaction; throw an exception if no current transaction exists.
  • PROPAGATION_REQUIRES_NEW – Create a new transaction, suspending the current transaction if one exists.
  • PROPAGATION_NOT_SUPPORTED – Do not support a current transaction; rather always execute non-transactionally.
  • PROPAGATION_NEVER – Do not support a current transaction; throw an exception if a current transaction exists.
  • PROPAGATION_NESTED – Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else.
In most cases, you may just need to use the PROPAGATION_REQUIRED.





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

16.<context:annotation-config/>
17.<!-- Add this tag to enable annotations transactions -->
18.<tx:annotation-driven  transaction-manager="transactionManager"/>
19.<bean id="transactionManager"
20.  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
21.  <property name="dataSource" ref="dataSource"></property>
22.</bean>
23.<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
24.  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
25.  <property name="url" value="jdbc:mysql://localhost:3306/apu"></property>
26.  <property name="username" value="root"></property>
27.  <property name="password" value=""></property>
28.</bean>
29.  
30.<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
31.  <property name="dataSource" ref="dataSource"></property>
32.</bean>
33.<bean id="userDao"   class="springjdbc.transactions.declarative.annotations.AnnotatedUserDao">
34.  <property name="jdbcTemplate" ref="jdbcTemplate"></property>
35.</bean>
36.                         
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

1.  /**
2.   * @author achauhan
3.   */
4.  @Transactional
5.  public class AnnotatedUserDao implements IUserDao {
6.  private JdbcTemplate jdbcTemplate;
7.   
8.  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
9.    this.jdbcTemplate = jdbcTemplate;
10.}
11.  
12.public void deleteUser(int uid) {
13.  String delQuery = "delete from users where id = ?";
14.  jdbcTemplate.update(delQuery, new Object[] { uid });
15. 
16.}
17. 
18.public int insertUser(User user) {
19.  String inserQuery = "insert into users (username, password, enabled , id) values (?, ?, ?, ?) ";
20.  Object[] params = new Object[] { user.getUserName(),
21.                         user.getPassword(), user.isEnabled(), user.getId() };
22.  int[] types = new int[] { Types.VARCHAR, Types.VARCHAR, Types.BIT,
23.                         Types.INTEGER };
24.  int number = jdbcTemplate.update(inserQuery, params, types);
25.  return number;
26.}
27. 
28.// override the class level transactional behaviour for select method
29.@Transactional(readOnly = true)
30.public User selectUser(int uid) {
31.// for all the RuntimeExceptions the transactions will be automatically
32.// rolled back
33.  throw new RuntimeException("A runtime exception");
34. 
35.}
36. 
37.public int updateUser(User user) throws Exception {
38.  throw new Exception("A checked exception");
39.}
40.                         
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)
13.20:57:29,141 TRACE [TransactionInterceptor] Getting transaction for [springjdbc.IUserDao.selectUser]
14.20:57:29,142 TRACE [TransactionInterceptor] Completing transaction for [springjdbc.IUserDao.selectUser] after exception: java.lang.RuntimeException: A runtime exception
15.20:57:29,142 TRACE [RuleBasedTransactionAttribute] Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: A runtime exception
16.20:57:29,142 TRACE [RuleBasedTransactionAttribute] Winning rollback rule is: null
17.20:57:29,142 TRACE [RuleBasedTransactionAttribute] No relevant rollback rule found: applying default rules
18.20:57:29,142 DEBUG [DataSourceTransactionManager] Initiating transaction rollback
19.         
@Transactional(readOnly = true,noRollbackFor=RuntimeException.class)
13.21:25:07,694 TRACE [TransactionInterceptor] Getting transaction for [springjdbc.IUserDao.selectUser]
14.21:25:07,695 TRACE [TransactionInterceptor] Completing transaction for [springjdbc.IUserDao.selectUser] after exception: java.lang.RuntimeException: A runtime exception
15.21:25:07,695 TRACE [RuleBasedTransactionAttribute] Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: A runtime exception
16.21:25:07,696 TRACE [RuleBasedTransactionAttribute] Winning rollback rule is: NoRollbackRuleAttribute with pattern [java.lang.RuntimeException]
17.21:25:07,697 DEBUG [DataSourceTransactionManager] Initiating transaction commit
18.         
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.

Ref:-
http://www.simplespringtutorial.com/springDeclarativeTransactions.html

No comments:

Post a Comment