Spring的事务管理
Spring提供以下两种方式管理事务。
10.1声明式事务管理(基于配置方式实现事务控制)
1)以8.9案例为例,在applicationContext.xml配置文件中使用xml方式配置事务:
<!--事务管理配置-->
<!--定义事务管理Bean(用于管理事务),不用我们写了,直接用Spring提供的类-->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<!-- 注入session资源 -->
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 定义方面和通知,直接使用Spring提供的命名空间:xmlns:tx=http://.../schema/tx -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--可以指定目标对象中不同方法采用不同的事务管理机制。注意:name要根据目标对象中的方法名写。read-only="true":只读事务,只能查询。propagation="REQUIRED"为默认值其他可取的值见10.3节 -->
<tx:attributes> <!--注释中的是给DAO添加事务,但不好!没注释的是给Action加-->
<!-- <tx:method name="save" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/> -->
<!-- action中execute方法都采取REQUIRED,而REQUIRED把默认的只读操作模式改了,此时可增、删、改、查。由于NetCTOSS项目没加Service组件,所以把事务加到Action上,否则就是给Service加的。而不加在DAO中是因为有些操作可能要执行多个DAO共同完成一项功能,如果加在DAO中,那么里面的一个方法就是一个事务(会提交),那么当该功能中途出现问题,则之前的操作将无法回滚了! -->
<tx:method name="execute" propagation="REQUIRED"/>
<!--其他没有考虑到的按默认的事务管理机制值-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--定义切入点,AOP切入--><!--proxy-target-class="true":表示强制采用CGLIB方式生成代理类,若不写则容器会根据是否有接口,而去选择用哪种技术产生代理类,但这样就会有问题!如:Action继承BaseAction,而BaseAction实现某个接口,那么容器选择的代理类技术而产生的代理Action是没有原来Action中的方法的!若是作用在DAO上,则可不写 -->
<aop:config proxy-target-class="true"><!-- 类型匹配 -->
<aop:pointcut id="actionPointcut" expression="within(com.tarena.netctoss.action..*)" />
<!-- 将切入点和通知结合 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="actionPointcut"/>
</aop:config>
2)以8.9案例为例,在applicationContext.xml配置文件中使用注解方式配置:
step1:定义HibernateTransactionManager(事务管理)Bean组件
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<!-- 注入session资源 -->
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
step2:开启事务的注解配置
<!-- 开启事务注解配置 --> <!-- 指明让txManager来管理事务 -->
<tx:annotation-driven proxy-target-class="true" transaction-manager="txManager"/>
step3:然后在业务组件的类定义前或方法中使用@Transactional注解即可,例如:
①AddCostAction,在类定义前使用(对类中除了get/set方法外的所有方法,都使用相同的事务管理)
@Transactional(propagation=Propagation.REQUIRED)
public class AddCostAction extends BaseAction{ …… }
②DeleteCostAction,在方法前使用
@Transactional(propagation=Propagation.REQUIRED)
public String execute() throws DAOException{ …… }
③UpdateCostAction,在类定义前使用
@Transactional(propagation=Propagation.REQUIRED)
public class UpdateCostAction extends BaseAction { …… }
④ListCostAction,在方法前使用
@Transactional(readOnly=true,propagation=Propagation.REQUIRED)
public String execute() throws Exception { …… }
- 注意事项:如果将Action当作目标,需要在<tx:annotation-driven>添加proxy-target-class="true"属性,表示不管有没有接口,都采用CGLIB方式生成代理类。
10.2编程式事务管理(基于Java编程实现事务控制),不推荐用!
主要是利用transactionTemplate的execute()方法,以回调方式将多个操作封装在一个事务中。
10.3 Spring中常用的事务类型
1)REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是默认值。
2)SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
3)MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
4)REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
5)NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6)NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7)NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED类似的操作。拥有多个可以回滚的保存点,内部回滚不会对外部事务产生影响。只对DataSourceTransactionManager有效。