聲明式事務管理詳解

轉載自:https://www.cnblogs.com/LarryBlogger/p/5969943.html

spring的事務處理分爲兩種:

    1、編程式事務:在程序中控制事務開始,執行和提交;(不建議使用,所以這裏我就不說明太多)    

    2、聲明式事務:在Spring配置文件中對事務進行配置,無須在程序中寫代碼;(建議使用)
        我對”聲明式“的理解是這樣的:Spring配置文件中定義好了這樣一個規則,
      這個規則可以指定對哪些類的哪些方法在執行的時候添加事務控制,並配置好了事務的相關執行屬性,
      就是在這些類的這些方法執行的時候隱式地添加事務開始、執行、提交或回滾的代碼(當然我們看不到)
      聲明式事務又分了兩種寫法:
        2.1、xml配置文件
        2.2、註解
   下面我們首先講解下在xml配置文件中如何配置聲明式事務管理
複製代碼
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"    
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
        xmlns:p="http://www.springframework.org/schema/p"  
        xmlns:aop="http://www.springframework.org/schema/aop"   
        xmlns:context="http://www.springframework.org/schema/context"  
        xmlns:jee="http://www.springframework.org/schema/jee"  
        xmlns:tx="http://www.springframework.org/schema/tx"  
        xsi:schemaLocation="    
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd  
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
    <!-- 類似於財務部門一樣,類就是錢,所有需要類的實例都由srping去管理 -->
    <!-- <context:component-scan>:
        有一個use-default-filters屬性,該屬性默認爲true,
        這就意味着會掃描指定包下的全部的標有註解的類,並註冊成bean.
        可以發現這種掃描的粒度有點太大,如果你只想掃描指定包下面的Controller,
        該怎麼辦?此時子標籤<context:incluce-filter>就起到了勇武之地。如下所示
        <context:component-scan base-package="news" use-default-filters="false">
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
        如果use-dafault-filters在上面並沒有指定,默認就爲true,
        也就意味着你現在加<context:exclude-filter/>跟沒加是一樣的
        所有你要記住,你若想要用到<context:component-scan>的子標籤,
        必須要把use-dafault-filters的值改爲false
        當然還有一個是與之相反的而已這裏就不囉嗦了
        上面這一對解釋換成一句話就是:
            Use-dafault-filters=”false”的情況下:<context:exclude-filter>指定的不掃描,<context:include-filter>指定的掃描
    <context:component-scan>的base-package屬性作用:設置要被掃描的包 -->
    
    <!-- (本案例不用到,只是用了一個全盤掃描,以上內容只是爲了讓大家瞭解它) -->
    
    <context:component-scan base-package="news.."/>
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!-- <tx:annotation-driven transaction-manager="transactionManager"/> -->

    <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <!-- 每300秒檢查所有連接池中的空閒連接 -->
        <property name="idleConnectionTestPeriod" value="300"/>
        <!-- 最大空閒時間,900秒內未使用則連接被丟棄。若爲0則永不丟棄 -->
        <property name="maxIdleTime" value="900"/>
        <!-- 最大連接數 -->
        <property name="maxPoolSize" value="2"/>
    </bean>
    
    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="myDataSource"/>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.connection.autocommit">false</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
        <property name="mappingResources">
            <list>
                <value>news/entity/News.hbm.xml</value>
            </list>
        </property>
    </bean>
    
    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
         <!--  創建事務管理器, 管理sessionFactory(因爲所有的session都是從sessionFactory獲取的) -->
         <property name="sessionFactory" ref="sessionFactory" />
     </bean>
    <!--  配置通知, 那些方法需要切入什麼類型的事務 -->     
    <tx:advice id="advice" transaction-manager="transactionManager">
         <tx:attributes>
             <tx:method name="add*" propagation="REQUIRED"/>
             <tx:method name="del*" propagation="REQUIRED"/>
             <tx:method name="update*" propagation="REQUIRED"/>
             <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
         </tx:attributes>
     </tx:advice>
     
     <!-- 配置切面表達式, 並且讓 tx與切面表達式合二爲一 -->
     <aop:config>
         <!-- 表達式, 定義哪個包的哪些類需要切入事務,但是此處並且沒有制定類中哪些方法,需要切入什麼樣 事務 -->
         <aop:pointcut expression="execution(* news.service.*.*(..))" id="pointcut" />
         <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
     </aop:config>
</beans>
            
複製代碼

   相信這段代碼對於我們初學者來說不是那麼容易看懂,下面我來給大家分析吧:

    1、創建事務管理器

 

  2、配置通知

  

<tx:attributes/>
屬性必須默認值 描述
name 要切入的方法名,可以用通配符
propagation不是REQUIRED事務傳播行爲
isolation不是DEFAULT事務隔離級別
timeout不是-1事務超時的時間(以秒爲單位)
read-only不是false事務是否只讀?
rollback-for不是 將被觸發進行回滾的 Exception(s);以逗號分開。 如:'news.serviceImpl'
no-rollback-for不是  被觸發進行回滾的 Exception(s);以逗號分開。 如:'news.serviceImpl'
  
  3、配置切面表達式, 並且讓 tx與切面表達式合二爲一 

    

  

複製代碼
我解釋一下execution(* news.service.*.*(..))"中幾個通配符的含義:

第一個 * —— 通配 任意返回值類型
第二個 * —— 通配 包news.service下的任意class
第三個 * —— 通配 包news.service下的任意class的任意方法
第四個 .. —— 通配 方法可以有0個或多個參數

綜上:包news.service下的任意class的具有任意返回值類型、任意數目參數和任意名稱的方法
複製代碼

 

  做到這裏xml方式的事務管理基本就做完了,還差最後一步,那就是導入它相關的缺包(無論哪種形式的事務管理都要導入這些包)

    

    如果沒有這些包的朋友們可以去一下網址下載:http://pan.baidu.com/s/1eSlyY1G

 

最後再給大家講一下註解形式的聲明式事務管理吧

  註解形式的聲明式事務管理只要在applicationContext.xml這份文件裏面加入一句

    <tx:annotation-driven transaction-manager="transactionManager"/>

  就可以從上面的代碼中把下面寫的那一大串xml去掉了,

 

複製代碼
<tx:advice id="advice" transaction-manager="transactionManager">
         <tx:attributes>
             <tx:method name="add*" propagation="REQUIRED"/>
             <tx:method name="del*" propagation="REQUIRED"/>
             <tx:method name="update*" propagation="REQUIRED"/>
             <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
         </tx:attributes>
 </tx:advice>
     
     配置切面表達式, 並且讓 tx與切面表達式合二爲一
     <aop:config>
         表達式, 定義哪個包的哪些類需要切入事務,但是此處並且沒有制定類中哪些方法,需要切入什麼樣 事務
         <aop:pointcut expression="execution(* news.service.*.*(..))" id="pointcut" />
         <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
     </aop:config>
複製代碼

 

 

 

 

有人會問,那怎麼才能實現事務管理呢?

    很簡單,就不如你的那個類裏面的全部方法都要加入事務管理,就可以直接在此類上面加入一個@Transactional註解就可以了

    如果你只想一個方法加入事務管理,也可以直接單獨在一個方法上面加入@Transactional註解

    當然,這個註解還有一些屬性比較常用的

參數名稱功能描述
readOnly該屬性用於設置當前事務是否爲只讀事務,設置爲true表示只讀,false則表示可讀寫,默認值爲false。例如:@Transactional(readOnly=true)
rollbackFor

該屬性用於設置需要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,則進行事務回滾。例如:

指定單一異常類:@Transactional(rollbackFor=RuntimeException.class)

指定多個異常類:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

該屬性用於設置需要進行回滾的異常類名稱數組,當方法中拋出指定異常名稱數組中的異常時,則進行事務回滾。例如:

指定單一異常類名稱:@Transactional(rollbackForClassName="RuntimeException")

指定多個異常類名稱:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollbackFor

該屬性用於設置不需要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,不進行事務回滾。例如:

指定單一異常類:@Transactional(noRollbackFor=RuntimeException.class)

指定多個異常類:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

該屬性用於設置不需要進行回滾的異常類名稱數組,當方法中拋出指定異常名稱數組中的異常時,不進行事務回滾。例如:

指定單一異常類名稱:@Transactional(noRollbackForClassName="RuntimeException")

指定多個異常類名稱:

@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

propagation

該屬性用於設置事務的傳播行爲,具體取值可參考下面

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation該屬性用於設置底層數據庫的事務隔離級別,事務隔離級別用於處理多事務併發的情況,通常使用數據庫的默認隔離級別即可,基本不需要進行設置
timeout該屬性用於設置事務的超時秒數,默認值爲-1表示永不超時

 

事物傳播行爲介紹: 

  @Transactional(propagation=Propagation.REQUIRED) :如果有事務, 那麼加入事務, 沒有的話新建一個(默認情況下)
  @Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不爲這個方法開啓事務
  @Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事務,都創建一個新的事務,原來的掛起,新的執行完畢,繼續執行老的事務
  @Transactional(propagation=Propagation.MANDATORY) :必須在一個已有的事務中執行,否則拋出異常
  @Transactional(propagation=Propagation.NEVER) :必須在一個沒有的事務中執行,否則拋出異常(與Propagation.MANDATORY相反)
  @Transactional(propagation=Propagation.SUPPORTS) :如果其他bean調用這個方法,在其他bean中聲明事務,那就用事務.如果其他bean沒有聲明事務,

 

 注意:
在以下情況中spring的事務管理會失效:
  ● private 方法無法添加事務管理.
  ● final 方法無法添加事務管理.
  ● static 方法無法添加事務管理.
  ● 當繞過代理對象, 直接調用添加事務管理的方法時, 事務管理將無法生效.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章