Spring配置--tx事务配置方式
前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识。通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的。
总结如下:
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。
DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。
具体如下图:
根据代理机制的不同,总结了五种Spring事务的配置方式,配置文件如下:
第一种方式:每个Bean都有一个代理
1 <!-- 定义事务管理器(声明式的事务) -->
2 <bean id="transactionManager"
3 class="org.springframework.orm.hibernate3.HibernateTransactionManager">
4 <property name="sessionFactory" ref="sessionFactory" />
5 </bean>
6
7 <!-- 配置DAO -->
8 <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
9 <property name="sessionFactory" ref="sessionFactory" />
10 </bean>
11
12 <bean id="userDao"
13 class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
14 <!-- 配置事务管理器 -->
15 <property name="transactionManager" ref="transactionManager" />
16 <property name="target" ref="userDaoTarget" />
17 <property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />
18 <!-- 配置事务属性 -->
19 <property name="transactionAttributes">
20 <props>
21 <prop key="*">PROPAGATION_REQUIRED</prop>
22 </props>
23 </property>
24 </bean>
第二种方式:所有Bean共享一个代理基类
1 <!-- 定义事务管理器(声明式的事务) -->
2 <bean id="transactionManager"
3 class="org.springframework.orm.hibernate3.HibernateTransactionManager">
4 <property name="sessionFactory" ref="sessionFactory" />
5 </bean>
6
7 <bean id="transactionBase"
8 class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
9 lazy-init="true" abstract="true">
10 <!-- 配置事务管理器 -->
11 <property name="transactionManager" ref="transactionManager" />
12 <!-- 配置事务属性 -->
13 <property name="transactionAttributes">
14 <props>
15 <prop key="*">PROPAGATION_REQUIRED</prop>
16 </props>
17 </property>
18 </bean>
19
20 <!-- 配置DAO -->
21 <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
22 <property name="sessionFactory" ref="sessionFactory" />
23 </bean>
24
25 <bean id="userDao" parent="transactionBase" >
26 <property name="target" ref="userDaoTarget" />
27 </bean>
第三种方式:使用拦截器
1 <!-- 定义事务管理器(声明式的事务) -->
2 <bean id="transactionManager"
3 class="org.springframework.orm.hibernate3.HibernateTransactionManager">
4 <property name="sessionFactory" ref="sessionFactory" />
5 </bean>
6
7 <bean id="transactionInterceptor"
8 class="org.springframework.transaction.interceptor.TransactionInterceptor">
9 <property name="transactionManager" ref="transactionManager" />
10 <!-- 配置事务属性 -->
11 <property name="transactionAttributes">
12 <props>
13 <prop key="*">PROPAGATION_REQUIRED</prop>
14 </props>
15 </property>
16 </bean>
17
18 <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
19 <property name="beanNames">
20 <list>
21 <value>*Dao</value>
22 </list>
23 </property>
24 <property name="interceptorNames">
25 <list>
26 <value>transactionInterceptor</value>
27 </list>
28 </property>
29 </bean>
30
31 <!-- 配置DAO -->
32 <bean id="userDao" class="com.bluesky.spring.dao.UserDaoImpl">
33 <property name="sessionFactory" ref="sessionFactory" />
34 </bean>
第四种方式:使用tx标签配置的拦截器
1 <context:annotation-config />
2 <context:component-scan base-package="com.bluesky" />
3
4 <bean id="sessionFactory"
5 class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
6 <property name="configLocation" value="classpath:hibernate.cfg.xml" />
7 <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
8 </bean>
9
10 <!-- 定义事务管理器(声明式的事务) -->
11 <bean id="transactionManager"
12 class="org.springframework.orm.hibernate3.HibernateTransactionManager">
13 <property name="sessionFactory" ref="sessionFactory" />
14 </bean>
15
16 <tx:advice id="txAdvice" transaction-manager="transactionManager">
17 <tx:attributes>
18 <tx:method name="*" propagation="REQUIRED" />
19 </tx:attributes>
20 </tx:advice>
21
22 <aop:config proxy-target-class="true"
>
23 <aop:pointcut id="interceptorPointCuts"
24 expression="execution(* com.bluesky.spring.dao.*.*(..))" />
25 <aop:advisor advice-ref="txAdvice"
26 pointcut-ref="interceptorPointCuts" />
27 </aop:config>
这里需要特别注意的是,我们需要在标签中将proxy-target-class配置成true,否则会出现和上一篇文章相同的错误:我们定义的类无法转换成代理类
这里我们通过来配置我们的事务增强属性。在标签中,常见属性及其说明如下,其中,除了name属性是必选外,其他都是可选的:
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
- TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
- TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
- TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
- TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
- TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
- TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。
只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。
spring事务回滚规则:指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。
默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。
第五种方式:全注解
1 <context:annotation-config />
2 <context:component-scan base-package="com.bluesky" />
3
4 <tx:annotation-driven transaction-manager="transactionManager"/>
5
6 <bean id="sessionFactory"
7 class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
8 <property name="configLocation" value="classpath:hibernate.cfg.xml" />
9 <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
10 </bean>
11
12 <!-- 定义事务管理器(声明式的事务) -->
13 <bean id="transactionManager"
14 class="org.springframework.orm.hibernate3.HibernateTransactionManager">
15 <property name="sessionFactory" ref="sessionFactory" />
16 </bean>
此时在DAO上需加上@Transactional注解,如下:
1 package com.bluesky.spring.dao;
2
3 import java.util.List;
4
5 import org.hibernate.SessionFactory;
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
8 import org.springframework.stereotype.Component;
9
10 import com.bluesky.spring.domain.User;
11
12 @Transactional
13 @Component("userDao")
14 public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
15
16 public List<User> listUsers() {
17 return this.getSession().createQuery("from User").list();
18 }
19
20
21 }