spring service層事務管理小結
阿新 • • 發佈:2018-12-10
前言:
選擇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();語句,手動回滾,這樣上層就無需去處理異常。