1. 程式人生 > >Spring框架深入(三)--事務

Spring框架深入(三)--事務

ssi new port 復讀 控制 級別 實現 inter 就是

一、事務的概念

  1、事務是什麽

   (1)、作為單個邏輯工作單元執行的一系列操作(一組SQL會成為一個事務),是並發控制的單位,要麽全部成功,要麽全部失敗

   (2)、如銀行轉賬(需要兩個update)/網上商城購物

  2、事務的特征

   (1)、原子性:所有的操作會被看成一個邏輯單元,要麽全部成功,要麽全部失敗

   (2)、一致性:事務在完成時,必須使所有的數據都保持一致狀態,保證數據的完整性

   (3)、隔離性:與並發有關,事務之間的相互影響—隔離級別

   (4)、持久性:事務結束後,結果是可以固化的

二、事務隔離

  技術分享圖片

  1、事務隔離用於處理事務之間的並發問題

  2、事務的隔離級別

   (1)、未授權讀取

   (2)、授權讀取

   (3)、可重復讀取

   (4)、序列化:隔離級別最高的

  3、事務隔離的實現:

   (1)、悲觀鎖:基於數據庫的鎖,不能操作數據

    a、悲觀鎖是讀取的時候為後面的更新加鎖,之後再來的讀操作都會等待。這種是數據庫鎖。

    b、悲觀鎖是數據庫實現,他阻止一切數據庫操作。

    c、在實際生產環境裏邊,如果並發量不大且不允許臟讀,可以使用悲觀鎖解決並發問題;

   (2)、樂觀鎖:不同的事務可以看到同一對象的不同歷史版本

    a、樂觀鎖是一種思想,是基於版本號機制的,具體實現是,表中有一個版本字段,第一次讀的時候,獲取到這個字段。處理完業務邏輯開始更新的時候,需要再次查看該字段的值是否和第一次的一樣。如果一樣更新,反之拒絕。之所以叫樂觀,因為這個模式沒有從數據庫加鎖。

    b、樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量;

    c、在實際生產環境中,如果系統的並發非常大的話,悲觀鎖定會帶來非常大的性能問題,所以我們就要選擇使用樂觀鎖。

三、B/S中的事務

  1、一個請求對應一個業務,一個業務其實就應該是一個事務

  2、一個請求對應一個事務

  3、一個事務----MyBatis中的事務與sqlSession相關

  4、一個請求對應著啟動一個線程,一個線程對應一個事務

   (1)、當前請求線程所執行的所有操作都是屬於同一個事務的,使用的是同一個sqlSession

   (2)、dao的所有操作應該是基於同一個sqlSession,這些操作才構成一個事務;

  5、一個線程對應著同一個sqlSession:

    如何讓一個線程中得到的sqlSession對象是同一個呢?使用ThreadLocal

  6、ThreadLocal

   (1)、當前線程變量:key/value

   (2)、將sqlSession放入線程上下文空間,線程會執行請求要做的所有方法(很多個dao操作),每次的dao操作所使用的sqlSession都從當前線程上下文取得;

   (3)、使用原理/步驟:

    a、每個dao在執行的時候,會使用getSqlSession來獲得會話

    b、判斷當前線程中是否有session,如果有的話,就用當前線程的session。如果沒有的話,就會創建session放入當前線程,同時返回session;

    c、繼續執行下一個dao操作的時候,因為是屬於同一個請求線程的,所以可以從當前線程裏拿到同一個session,從而形成事務的概念。

/*
 * 當前線程上下文空間
 * 將session放入當前線程變量中
 * 如果當前線程有該對象,就直接拿來用
 * 如果沒有,才去新建對象
 * */
public class SessionFactoryUtil {
    private static ThreadLocal threadLocal = new ThreadLocal();    
    public static SqlSession getSqlSession() {    
        SqlSession session = (SqlSession) threadLocal.get();
        if(session!=null) {
            return session;
        }
        else{
            session=new SqlSession();
            threadLocal.set(session);
            return session;
        }
    }
}
public void run() {
    //這兩個dao操作時屬於同一個事務的,也就是dao操作所使用的sqlSession是同一個
    userDao.buy();
    productDao.updatePruduct();
}

  7、B/S中要實現事務,需要將sqlSession放入ThreadLocal(當前線程上下文)中

   通過servletFilter實現請求到達的時候,創建session放入ThreadLocal

四、Spring中的事務

  1、事務其實是一個切面的存在,只需要在Spring中配置AOP就可以實現事務了

  2、AOP

   (1)、核心業務:自己編寫

   (2)、切面:事務這個切面Spring已經提供了實現:不需要自己編寫

    a、Spring已經提供了實現事務的通知,配置為bean

    b、事務管理平臺:確定事務切面用在哪個平臺

    c、事務策略定義:事務的屬性(隔離級別、傳播性)

    d、事務狀態

  3、在Spring中實現事務:通過配置AOP實現

   (1)、將Spring提供的通知類配置到核心業務線

   (2)、基於註解進行配置

   (3)、基於AOP的配置文件進行配置

  技術分享圖片

  4、PlatformTransactionManager

   確定要做的事務是基於哪個平臺(JDBC、Hibernate、MyBatis、JPA)

  技術分享圖片

五、Spring+MyBatis事務管理

  1、Spring+MyBatis集成後,默認每個操作都是產生一個新的SqlSession,不構成事務概念,每個操作就是一個獨立的事務

  2、事務都是基於service層

  3、Spring中事務AOP的配置

   (1)、首先,我們這兒有一個Author類(實現類get,set方法),以及AuthorMapper接口

public class Author {
    private int id;
    private String username;
    private String password;
    private String email;
    private String bio;
}
public interface AuthorMapper {
    public Author findById(int id);

    public void insertAuthor(Author aut);
}

    接口中有兩個方法,分別是查找所有和插入

    如果我們就這樣運行,他就會創建兩個SqlSession分別處理兩個方法;

   (3)、在核心配置文件中進行事務AOP的配置

<!-- 
    AOP 事務配置 
        核心業務:service——已完成
        切面bean:Spring提供支持類,進行配置
        建立切入點aop關聯,進行配置
-->
    
<!-- 配置事務管理器:切面的一部分 -->
<bean id="transManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
    
<!-- 
    配置事務策略狀態:切面的一部分 
    事務通知的配置
-->
<tx:advice id="txAdvice" transaction-manager="transManager">
    <tx:attributes>
        <!-- 
            對應的方法與事務的使用 
            REQUIRED:在事務中執行,如果事務不存在,則會重新創建一個
            SUPPORTS:使用當前的環境執行,如果當前存在事務,則會使用這個事務,如果當前沒有這個事務,則不使用事務
        -->
        <tx:method name="add*" propagation="REQUIRED"/>
        <tx:method name="insert*" propagation="REQUIRED"/>
        <tx:method name="del*" propagation="REQUIRED"/>
        <tx:method name="update*" propagation="REQUIRED"/>
        <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
    </tx:attributes>
</tx:advice>
    
<!-- 核心業務與事務關聯起來 -->
<aop:config>
    <!-- 切入點 -->
    <aop:pointcut expression="execution(* service.*.*.*(..))" id="transPointCut"/>
    <!-- 關聯操作 -->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="transPointCut"/>
</aop:config>    

    如果是對於hibernate而言,到這兒就已經可以實現事務了。但是,對於MyBatis而言,還需要繼續進行配置,有兩種配置方法;

    a、基於註解實現事務

<!-- 配置註解驅動,標註@Transactional的類和方法都具有事務性 -->
<tx:annotation-driven transaction-manager="transManager"/>

    只需要在信心配置文件中配置註解驅動,並且在實現類上加上@Transactional就可以了;

@Transactional
@Override
public void doFindAndInsert() {
    Author aut=new Author();
    aut.setBio("test");
    aut.setEmail("test");
    aut.setPassword("test");
    aut.setUsername("test");
    authorMapper.insertAuthor(aut);
                
    //報錯的時候,回滾
    int i=5/0;
                
    Author author = authorMapper.findById(1);
    System.out.println(author);
    return null;    
}

    運行結果:

    技術分享圖片

    b、基於事務管理模板實現事務

     配置一個支持事務的模板bean

<!-- 
    基於事務模板
    用於支持事務的模板bean
 -->
<bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <constructor-arg type="org.springframework.transaction.PlatformTransactionManager" ref="transManager"></constructor-arg>
</bean>

     實現類:

public void doFindAndInsert() {
    txTemplate.execute(new  TransactionCallback<Integer>() {

        @Override
        public Integer doInTransaction(TransactionStatus arg0) {
            // TODO Auto-generated method stub
            Author aut=new Author();
            aut.setBio("test");
            aut.setEmail("test");
            aut.setPassword("test");
            aut.setUsername("test");
            authorMapper.insertAuthor(aut);
                
            //報錯的時候,回滾
            int i=5/0;
                
            Author author = authorMapper.findById(1);
            System.out.println(author);
            return null;
        }
    });
}

     運行結果:

    技術分享圖片

PS:因作者能力有限,如有誤還請諒解;

Spring框架深入(三)--事務