1. 程式人生 > >spring service層事務管理小結

spring service層事務管理小結


前言:
    選擇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();語句,手動回滾,這樣上層就無需去處理異常。