spring事物配置,聲明式事務管理和基於@Transactional註解的使用 [轉]

spring支持編程式事務管理和聲明式事務管理兩種方式。java

   編程式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對於編程式事務管理,spring推薦使用TransactionTemplate。node

        聲明式事務管理創建在AOP之上的。其本質是對方法先後進行攔截,而後在目標方法開始以前建立或者加入一個事務,在執行完目標方法以後根據執行狀況提交或者回滾事務。聲明式事務最大的優勢就是不須要經過編程的方式管理事務,這樣就不須要在業務邏輯代碼中摻瑣事務管理的代碼,只需在配置文件中作相關的事務規則聲明(或經過基於@Transactional註解的方式),即可以將事務規則應用到業務邏輯中。mysql

       顯然聲明式事務管理要優於編程式事務管理,這正是spring倡導的非侵入式的開發方式。聲明式事務管理使業務代碼不受污染,一個普通的POJO對象,只要加上註解就能夠得到徹底的事務支持。和編程式事務相比,聲明式事務惟一不足地方是,後者的最細粒度只能做用到方法級別,沒法作到像編程式事務那樣能夠做用到代碼塊級別。可是即使有這樣的需求,也存在不少變通的方法,好比,能夠將須要進行事務管理的代碼塊獨立爲方法等等。程序員

         聲明式事務管理也有兩種經常使用的方式,一種是基於tx和aop名字空間的xml配置文件,另外一種就是基於@Transactional註解。顯然基於註解的方式更簡單易用,更清爽。spring

spring事務特性sql

spring全部的事務管理策略類都繼承自org.springframework.transaction.PlatformTransactionManager接口數據庫

 

其中TransactionDefinition接口定義如下特性:express

事務隔離級別編程

  隔離級別是指若干個併發的事務之間的隔離程度。TransactionDefinition 接口中定義了五個表示隔離級別的常量:數組

  • TransactionDefinition.ISOLATION_DEFAULT:這是默認值,表示使用底層數據庫的默認隔離級別。對大部分數據庫而言,一般這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級別表示一個事務能夠讀取另外一個事務修改但尚未提交的數據。該級別不能防止髒讀,不可重複讀和幻讀,所以不多使用該隔離級別。好比PostgreSQL實際上並無此級別。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級別表示一個事務只能讀取另外一個事務已經提交的數據。該級別能夠防止髒讀,這也是大多數狀況下的推薦值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級別表示一個事務在整個過程當中能夠屢次重複執行某個查詢,而且每次返回的記錄都相同。該級別能夠防止髒讀和不可重複讀。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:全部的事務依次逐個執行,這樣事務之間就徹底不可能產生干擾,也就是說,該級別能夠防止髒讀、不可重複讀以及幻讀。可是這將嚴重影響程序的性能。一般狀況下也不會用到該級別。

事務傳播行爲

      所謂事務的傳播行爲是指,若是在開始當前事務以前,一個事務上下文已經存在,此時有若干選項能夠指定一個事務性方法的執行行爲。在TransactionDefinition定義中包括了以下幾個表示傳播行爲的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED:若是當前存在事務,則加入該事務;若是當前沒有事務,則建立一個新的事務。這是默認值。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:建立一個新的事務,若是當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:若是當前存在事務,則加入該事務;若是當前沒有事務,則以非事務的方式繼續運行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行,若是當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,若是當前存在事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_MANDATORY:若是當前存在事務,則加入該事務;若是當前沒有事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_NESTED:若是當前存在事務,則建立一個事務做爲當前事務的嵌套事務來運行;若是當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。

事務超時

      所謂事務超時,就是指一個事務所容許執行的最長時間,若是超過該時間限制但事務尚未完成,則自動回滾事務。在 TransactionDefinition 中以 int 的值來表示超時時間,其單位是秒。

  默認設置爲底層事務系統的超時值,若是底層數據庫事務系統沒有設置超時值,那麼就是none,沒有超時限制。

事務只讀屬性

      只讀事務用於客戶代碼只讀但不修改數據的情形,只讀事務用於特定情景下的優化,好比使用Hibernate的時候。
默認爲讀寫事務。

spring事務回滾規則

     指示spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內拋出異常。spring事務管理器會捕捉任何未處理的異常,而後依據規則決定是否回滾拋出異常的事務。

 

@Transactional註解

                  @Transactional屬性 

屬性 類型 描述
value String 可選的限定描述符,指定使用的事務管理器
propagation enum: Propagation 可選的事務傳播行爲設置
isolation enum: Isolation 可選的事務隔離級別設置
readOnly boolean 讀寫或只讀事務,默認讀寫
timeout int (in seconds granularity) 事務超時時間設置
rollbackFor Class對象數組,必須繼承自Throwable 致使事務回滾的異常類數組
rollbackForClassName 類名數組,必須繼承自Throwable 致使事務回滾的異常類名字數組
noRollbackFor Class對象數組,必須繼承自Throwable 不會致使事務回滾的異常類數組
noRollbackForClassName 類名數組,必須繼承自Throwable 不會致使事務回滾的異常類名字數組

用法

       @Transactional 能夠做用於接口、接口方法、類以及類方法上。看成用於類上時,該類的全部 public 方法將都具備該類型的事務屬性,同時,咱們也能夠在方法級別使用該標註來覆蓋類級別的定義。

         雖然 @Transactional 註解能夠做用於接口、接口方法、類以及類方法上,可是 Spring 建議不要在接口或者接口方法上使用該註解,由於這隻有在使用基於接口的代理時它纔會生效。另外, @Transactional 註解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。若是你在 protected、private 或者默承認見性的方法上使用 @Transactional 註解,這將被忽略,也不會拋出任何異常。

 

各類屬性的意義: 

      REQUIRED:業務方法須要在一個容器裏運行。若是方法運行時,已經處在一個事務中,那麼加入到這個事務,不然本身新建一個新的事務。 

      NOT_SUPPORTED:聲明方法不須要事務。若是方法沒有關聯到一個事務,容器不會爲他開啓事務,若是方法在一個事務中被調用,該事務會被掛起,調用結束後,原先的事務會恢復執行。 

      REQUIRESNEW:無論是否存在事務,該方法總彙爲本身發起一個新的事務。若是方法已經運行在一個事務中,則原有事務掛起,新的事務被建立。 

      MANDATORY:該方法只能在一個已經存在的事務中執行,業務方法不能發起本身的事務。若是在沒有事務的環境下被調用,容器拋出例外。 

      SUPPORTS:該方法在某個事務範圍內被調用,則方法成爲該事務的一部分。若是方法在該事務範圍外被調用,該方法就在沒有事務的環境下執行。 

      NEVER:該方法絕對不能在事務範圍內執行。若是在就拋例外。只有該方法沒有關聯到任何事務,才正常執行。 

      NESTED:若是一個活動的事務存在,則運行在一個嵌套的事務中。若是沒有活動事務,則按REQUIRED屬性執行。它使用了一個單獨的事務,這個事務擁有多個能夠回滾的保存點。內部事務的回滾不會對外部事務形成影響。它只對DataSourceTransactionManager事務管理器起效。

 

@Transactional註解注意的幾點:

1 @Transactional 只能被應用到public方法上, 對於其它非public的方法,若是標記了@Transactional也不會報錯,但方法沒有事務功能.

2用 spring 事務管理器,由spring來負責數據庫的打開,提交,回滾.默認遇到運行期例外(throw new RuntimeException("註釋");)會回滾,即遇到不受檢查(unchecked)的例外時回滾;而遇到須要捕獲的例外(throw new Exception("註釋");)不會回滾,即遇到受檢查的例外(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查例外或說受檢查異常)時,需咱們指定方式來讓事務回滾 要想全部異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常}) .若是讓unchecked例外不回滾: @Transactional(notRollbackFor=RunTimeException.class)
以下:
@Transactional(rollbackFor=Exception.class) //指定回滾,遇到異常Exception時回滾
public void methodName() {
throw new Exception("註釋");

}
@Transactional(noRollbackFor=Exception.class)//指定不回滾,遇到運行期例外(throw new RuntimeException("註釋");)會回滾
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException("註釋");
}

三、@Transactional 註解應該只被應用到 public 可見度的方法上。 若是你在 protected、private 或者 package-visible 的方法上使用 @Transactional 註解,它也不會報錯, 可是這個被註解的方法將不會展現已配置的事務設置。


四、@Transactional 註解能夠被應用於接口定義和接口方法、類定義和類的 public 方法上。然而,請注意僅僅 @Transactional 註解的出現不足於開啓事務行爲,它僅僅 是一種元數據,可以被能夠識別 @Transactional 註解和上述的配置適當的具備事務行爲的beans所使用。上面的例子中,其實正是 <tx:annotation-driven/>元素的出現 開啓 了事務行爲。


五、Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 註解,而不要使用在類所要實現的任何接口上。你固然能夠在接口上使用 @Transactional 註解,可是這將只能當你設置了基於接口的代理時它才生效。由於註解是 不能繼承 的,這就意味着若是你正在使用基於類的代理時,那麼事務的設置將不能被基於類的代理所識別,並且對象也將不會被事務代理所包裝(將被確認爲嚴重的)。因 此,請接受Spring團隊的建議而且在具體的類上使用 @Transactional 註解。

 

下面就簡單的看以下一個例子完整的配置文件

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"    
 3         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
 4         xmlns:p="http://www.springframework.org/schema/p"  
 5         xmlns:aop="http://www.springframework.org/schema/aop"   
 6         xmlns:context="http://www.springframework.org/schema/context"  
 7         xmlns:jee="http://www.springframework.org/schema/jee"  
 8         xmlns:tx="http://www.springframework.org/schema/tx"  
 9         xsi:schemaLocation="    
10             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd  
11             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd  
12             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
13             http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd  
14             http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
15     <!-- 引入外部properties屬性文件 -->
16     <context:property-placeholder location="classpath:jdbc.properties"/>
17     
18     <!-- 原理:自動注入processor解析器,用來解析註解 -->
19     <!-- 
20     <context:annotation-config/>
21      -->
22      
23     <!-- 自動掃描包,也會自動注入解釋器,因此不須要 context:annotation-config-->
24     <context:component-scan base-package="news"/>
25     
26     <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
27         <!-- 注入鏈接池,包含了數據庫用戶名,密碼等等信息 -->
28         <property name="dataSource" ref="myDataSource"/>
29         
30         <!-- 配置Hibernate的其餘的屬性 -->
31         <property name="hibernateProperties">
32             <props>
33                 <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
34                 <prop key="hibernate.show_sql">true</prop>
35                 <prop key="hibernate.format_sql">true</prop>
36                 <prop key="hibernate.connection.autocommit">false</prop>
37                 <!-- 開機自動生成表 -->
38                 <prop key="hibernate.hbm2ddl.auto">update</prop>
39             </props>
40         </property>
41         <property name="packagesToScan">
42             <list>
43                 <value>news.entity</value>
44             </list>
45         </property>
46         <!-- 
47         <property name="mappingResources">
48             <list>
49                 <value>news/entity/News.hbm.xml</value>
50             </list>
51         </property>
52          -->
53     </bean>    
54      
55     <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
56         <property name="driverClass" value="${jdbc_MySQL.driver}"/>
57         <property name="jdbcUrl" value="${jdbc_MySQL.url}"/>
58         <property name="user" value="${jdbc_MySQL.user}"/>
59         <property name="password" value="${jdbc_MySQL.password}"/>
60         <!-- 每300秒檢查全部鏈接池中的空閒鏈接 -->
61         <property name="idleConnectionTestPeriod" value="300"></property>
62         <!-- 最大空閒時間,900秒內未使用則鏈接被丟棄。若爲0則永不丟棄 -->
63         <property name="maxIdleTime" value="900"></property>
64         <!-- 最大鏈接數 -->
65         <property name="maxPoolSize" value="2"></property>
66     </bean>
67     
68     <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
69         <property name="sessionFactory" ref="sessionFactory"/>
70     </bean> 
71     
72     <!--啓動spring事務註解功能-->
73     <tx:annotation-driven transaction-manager="transactionManager"/>
74     
75     <!-- 
76     <tx:advice id="txAdvice" transaction-manager="transactionManager">
77         <tx:attributes>
78             <tx:method name="add*" propagation="REQUIRED"/>
79             <tx:method name="del*" propagation="REQUIRED"/>
80             <tx:method name="mod*" propagation="REQUIRED"/>
81             <tx:method name="*" propagation="REQUIRED" read-only="true"/>
82         </tx:attributes>
83     </tx:advice>
84     
85     <aop:config>
86         <aop:pointcut expression="execution(* news.dao.*.*(..))" id="intercePointCuts"/>
87         <aop:advisor advice-ref="txAdvice" pointcut-ref="intercePointCuts"/>
88     </aop:config>
89     -->
90 </beans>
91             

如今就用註解方法來實現去掉一份實體類的映射文件

須要在applicationContext.xml這份配置文件裏自動掃描具體實體類的包

 

實體類的註解配置以下所示:

使用Spring的AOP註解功能,必須導入以下幾個包。aspectjrt.jar,aspectjweaver.jar,cglib-nodep.jar.

使用springAOP管理事務以後,在以前的DAO中須要把openSession獲取會話的方式改成getCurrentSession

//Session session=sessionFactory.openSession();
Session session=sessionFactory.getCurrentSession();

openSession與getCurrentSession二者的區別:

1.getCurrentSession的方式會在事務結束時自動關閉鏈接,而openSession則須要手動關閉鏈接。

2.採用getCurrentSession建立的session會綁定帶當前的線程中去,但openSession則不會。

採用@Transactional註解方式以下:

@Transactional    //放在這裏表示類的全部方法都加入事務管理  
public class NewsServiceImpl implements NewsService{
  ······
} 
//也能夠在單個方法上加註解
@Transactional(readOnly=true)    
public List showAllNews() {
  ······
}  

事務管理聲明註解配置以下

以上xml文件配置的方法換爲註解來實現,這裏須要這樣來配置:

還要配置一下實現註解功能

還能夠是在具體的實現方法上加實現註解功能

 

下面來講一下spring事務註解和xml文件實現註解的區別所在

這兩種實現事務註解各有優點,只是看程序員的編碼風格喜愛罷了,其中有的程序員喜愛spring事務註解編碼風格,而有的程序員就偏好於xml文件實現註解功能固然我仍是比較偏好於xml文件來實現註解功能。

對於這兩種都是實現事務註解來講,spring事務註解編碼風格相對就比較簡單,但是它與spring框架耦合在一塊兒了,對於以後的可維護性和可讀性沒那麼好;而對於xml文件實現註解是與spring框架沒有耦合在一塊兒,以後的可維護性和可讀性相對就好一點,但是編寫的代碼有點麻煩,還有就是實現的方法命名規範不能隨意進行更改。

 

有關注解就寫到這裏,若是還要想深刻的去學習實現註解功能,但願大家還要多點去

搜索網上關於註解的詳細講解,好好珍惜當今互聯網的資源學習。 謝謝!

相關文章
相關標籤/搜索