Spring --事務回滾

有這種業務需求:java

一次業務分三個步驟完成spring

步驟1:insert table1
成功後,執行update table2
成功後,執行update table3

執行邏輯確定以下數據庫

int success1 = insert table1;
if(success1 == 1)
{
    int success2 =  update table2;
    if(success2 == 1)
    {
        int success3 = update table3;
        if(success3 == 1)
        {
            //成功
        }else
            {
              //失敗3
            }
    }else
        {
            //失敗2
        }
}else
{
        //失敗1
}

如今,存在這種狀況,假設步驟1和步驟2都成功了,express

執行步驟3的時候,返回0,即success3 == 0,可是又沒有報異常,這個時候事物就不會回滾,即步驟1插入成功,步驟2也更新成功了,步驟3更新失敗,這時候返回給前臺的信息是此次操做失敗,可是步驟1和步驟2仍然影響了數據庫。app

解決辦法以下ui

方法0:自動回滾,controller層捕獲異常,且處理異常,加tryprototype

事物配置在service層,所以service層中的方法不作異常捕獲,而是放在上層(即controller層)捕獲、處理。代理

//controller層
try{
    //事物層方法
}catch{
    //異常處理
}

方法1:自動回滾,加try catchcode

事物配置在service層,service層的方法捕獲異常,而後跑出異常,讓aop去執行回滾
事務

//service層實現方法
try{
    insert table1;
    update table2;
    update table3;
}catch(Exception e)
{
    //拋出異常
    throw new RuntimeException(); 
}

方法2:手動回滾,我目前就採用這種方法

事物配置在service層,service層的方法捕獲異常,處理異常(即執行該事物回滾操做)。

//service層實現方法
import org.springframework.transaction.interceptor.TransactionAspectSupport;
//手動回滾
int success1 = insert table1;
if(success1 == 1)
{
    int success2 =  update table2;
    if(success2 == 1)
    {
        int success3 = update table3;
        if(success3 == 1)
        {
            //成功
        }else
            {
              //失敗3
              //手動回滾
              TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
    }else
        {
            //失敗2
            //手動回滾
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
}else
{
        //失敗1
        //手動回滾
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}


spring的事物配置以下

    <!-- ========================================分隔線========================================= -->
    <!-- 配置Spring的事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 攔截器方式配置事物 -->
    <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="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="regist*" 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>
    
    <aop:config>
        <!-- 匹配com.readygo.zbhealth.service.impl這個類下面的全部方法-->
        <aop:pointcut id="transactionPointcut" expression="execution(* com.readygo.zbhealth.service.impl.*Impl.*(..))" />
        <!--把事務控制在Service層-->
        <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
    </aop:config>


    <!-- 配置druid監控spring jdbc -->
    <bean id="druid-stat-interceptor" class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor">
    </bean>
    <bean id="druid-stat-pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">
        <property name="patterns">
            <list>
                <value>com.readygo.zbhealth.service.impl.*</value>
            </list>
        </property>
    </bean>
    <aop:config>
        <aop:advisor advice-ref="druid-stat-interceptor" pointcut-ref="druid-stat-pointcut" />
    </aop:config>


spring aop 異常捕獲原理

被攔截的方法須要顯式的拋出異常,且該異常沒有被處理,這樣aop代理才能捕獲到方法的異常,才能進行回滾;默認狀況下,aop只能捕獲runtimeexception()異常。

方法0

在controll層捕獲service層方法異常,controller層處理異常。

方法1

service捕獲service層方法異常,service層拋出異常,自動回滾。

方法2

service層捕獲service層方法異常,service層方法本身處理異常,手動回滾。這種方式上層不須要處理異常。

相關文章
相關標籤/搜索