天天看點

Spring學習(十四)Spring中如何使用事務?

一、為什麼要使用事務?

如果我們一個業務邏輯隻執行一次sql,是不需要使用事務的。但如果要執行多條sql語句才能完成一個業務邏輯的話,這個時候就要使用事務了。
因為這幾條sql可能有的執行成功,有的執行失敗。
而事務就是對一組sql語句進行統一的送出或復原操作,為了保證資料執行的一緻性,這組sql不是全部成功就是全部失敗。
           

舉個例子吧:

我們要實作轉賬的功能。首先要在賬戶a中扣100元,然後在賬戶b中加100元,這裡涉及兩次sql操作。大概像下面代碼這樣操作:

boolean flag1 = accountDao.minus(map)==;
            if(flag1){
                // 減成功
                map.put("toAccount", toAccount);
                boolean flag2 = accountDao.plus(map)==;
                if(flag2){
                    // 加成功
                    return true;
                }else{
                    /** 加失敗 [減生效了] 復原
                     *  為這個轉賬的過程添加事務控制
                    // 自定義異常
                    throw new PayException();
                }
            }else{
                // 減失敗
                return false;
            }
           

如果賬戶a減錢成功,賬戶b加錢失敗(比如賬戶輸入錯誤,資料庫中沒有這個賬戶,sql執行失敗), 這裡顯然要把a賬戶減的錢還回來。即復原。是以在這裡需要添加事務控制。

二、如何在spring中添加事務?

  • spring中的事務 作為 局部事務 , 配置方式依賴于持久層使用的技術

    spring整合jdbc

    spring整合hibernate

  • spring中即提供了程式設計式事務的管理方式,也提供了聲明式事務的管理方式:【程式設計式事務 TransactionTemplate 模闆類 将事務的管理過程封裝模闆類中】

    【聲明式事務 AOP】

    提供根接口 PlatFormTransactionManager 事務管理器接口

    用于描述spring中事務如何管理[如何建立、如何送出、如何復原]

  • 聲明式事務

    底層采用AOP技術實作,将事務管理過程(建立、送出、復原)封裝在一個事務通知bean[AfterAdvice ThrowsAdvice]中;

    通過在ioc容器中配置切入點的方式,将這個事務通知bean提供的事務管理功能引用給需要事務的核心業務邏輯方法(DAO)

在容器中添加配置如下:(這裡orm用的mybatis)

applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <context:component-scan base-package="com"/>

    <bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/etoak"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="ds"></property>
        <property name="mapperLocations">
            <list>
                <value>classpath:com/etoak/dao/AccountDaoIf-mapper.xml</value>
            </list>
        </property>
    </bean>

    <bean id="accountDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="sqlSessionFactory" ref="ssf"></property>
        <property name="mapperInterface" value="com.etoak.dao.AccountDaoIf"></property>
    </bean>

    <!-- 
        配置聲明式事務!
        1 aop命名空間、schema檔案
          tx命名空間、schame檔案(用于提供聲明式事務的支援)
        2 配置事務通知bean [Advice]
        [before after around throws]
            管理事務的使用方式[建立、送出、復原]
        transaction-manager: 設定事務管理器
        事務管理器 PlatFormTransactionManager
                - DataSourceTransactionManager
     -->
    <tx:advice id="tran" transaction-manager="tm">
        <tx:attributes>
            <!-- 
                tx:method 為不同類型的方法添加不同的事務屬性
             -->
            <tx:method name="pay"
                isolation="DEFAULT"
                propagation="REQUIRED"
                read-only="false"
                timeout="-1"
                rollback-for="com.etoak.util.PayException"/>
            <tx:method name="add*"/>
            <tx:method name="del*"/>
            <tx:method name="sel*" read-only="true"/>
            <tx:method name="update*" timeout="10"/>
        </tx:attributes>
    </tx:advice>

    <!-- 
        配置事務管理器bean
     -->
    <bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="ds"></property>
    </bean>

    <!-- 
        3 配置切入點 
            描述需要将通知[tran]提供的功能[事務管理功能]引用給哪個/哪些方法
     -->
    <aop:config>
        <aop:pointcut 
            expression="execution(* com.etoak.service.*.*(..))" 
            id="pc"/>
        <aop:advisor advice-ref="tran" pointcut-ref="pc"/>
    </aop:config>
</beans>
           

配置好了,還要寫一個異常類,在需要事務管理的地方抛出自己定義的異常,進而啟用事務。

public class PayException extends Exception{
    @Override
    public String getMessage() {
        return "減操作成功,加操作失敗,失敗原因:沒有這個賬戶.轉賬失敗,我要復原";
    }
}
           

在web.xml中添加異常頁面配置:

<error-page>
    <exception-type>com.etoak.util.PayException</exception-type>
    <location>/error.jsp</location>
  </error-page>
           

方法裡面添加事務管理:

public class PayService {

    @Autowired
    private AccountDaoIf accountDao;

    // 提供轉賬服務
    public boolean pay(String fromAccount , String toAccount , Double money)throws Exception{

        // 調用DAO
        double yue = accountDao.查詢餘額(fromAccount);
        if(yue>=money){
            Map map = new HashMap();
            map.put("fromAccount", fromAccount);
            map.put("money" , money);
            boolean flag1 = accountDao.minus(map)==;
            if(flag1){
                // 減成功
                map.put("toAccount", toAccount);
                boolean flag2 = accountDao.plus(map)==;
                if(flag2){
                    // 加成功
                    return true;
                }else{
                    /** 加失敗 [減生效了] 復原
                     *  為這個轉賬的過程添加事務控制
                     *  添加聲明式事務
                     *  以AOP的方式進行添加
                     *  将事務的管理過程封裝在一個事務通知bean
                     *  以配置、引用的方式将事務通知bean添加給需要事務的方法
                     *  切入點指向的是哪 : 服務層中Service對象提供的pay()
                     *  
                     *  聲明式事務復原的方式:檢測到異常時
                     */
                    // 自定義異常
                    throw new PayException();
                }
            }else{
                // 減失敗
                return false;
            }
        }else{
            return false;
        }
    }
}
           

繼續閱讀