前言:
选择spring作为开发的框架,很大一部分因素是spring框架完善的事务处理机制,spring的事务实现主要分为两种,一种是基于Dao层,另一种是基于Service层,前者是针对单个dao的持久化操作做了事务控制,控制粒度比较小,后者则是基于业务的原则性需求,将一个原子性业务的操作做了事务控制,本文主要针对service层事务配置进行说明:
方法一:基于注解的service层事务配置
spring-mybatis.xml中做如下配置:
1、首先配置数据源:
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" lazy-init="false">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
2、事务管理 : DataSourceTransactionManager dataSource:引用上面定义的数据源
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
3、使用声明式事务 transaction-manager:引用上面定义的事务管理器
<tx:annotation-driven transaction-manager="transactionManager" />
service层方法添加如下注解:
@Transactional( rollbackFor={Exception.class})
例:
@Service("cmdbOrderService")
public class CmdbOrderServiceImpl implements CmdbOrderService {
//@Transactional( rollbackFor={Exception.class})
public boolean disposeCmdbOrder(CmdbOrder cmdbOrder) {
//........
}
}
第二种方法:基于AOP代理的service层事务配置
1、首先配置数据源:
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" lazy-init="false">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
2、事务管理 : DataSourceTransactionManager dataSource:引用上面定义的数据源
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
3 配置事物的具体内容,
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="append*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="batchSave*" propagation="REQUIRED" />
<tx:method name="batchDel*" propagation="REQUIRED" />
<tx:method name="refreshUnrecovery*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="edit*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="repair" propagation="REQUIRED" />
<tx:method name="delAndRepair" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="dispose*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" />
<tx:method name="find*" propagation="SUPPORTS" />
<tx:method name="load*" propagation="SUPPORTS" />
<tx:method name="search*" propagation="SUPPORTS" />
<tx:method name="datagrid*" propagation="SUPPORTS" />
<tx:method name="*" propagation="SUPPORTS" />
</tx:attributes>
</tx:advice>
4 动态数据源事物aop,当service层方法满足上述正则,则开启事物
<aop:config proxy-target-class="true">
<aop:pointcut id="transactionPointcut" expression="execution(* com.wutongyu.service..*Impl.*(..))" />
<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" order="2"/>
</aop:config>
注意:捕获异常 事务的处理
默认情况下,spring事务只在发生未被捕获的RuntimeException时才回滚,如果有通过try-catch捕获异常,事物不会生效;只有在抛出 RuntimeException时,事物才会生效,如果要求方法内部必须进行捕捉,怎么处理呢?
(1)在catch语句中最后增加throw new RuntimeException(),手动抛出异常,以便aop捕获异常再去回滚,并且在service上层要继续捕获这个异常并处理。
(2)在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常。