1、事務執行的時候是在前面開啟事務,后面關閉事務,結束事務有兩種方式,一種是正常的提交事務,一種是出現問題回滾事務。
spring事務默認只有在拋出unchecked Exception才會回滾
UncheckedException包括error和runtimeException派生出的所有子類
2、什么時候才用事務?
對數據庫的數據進行批量或連表操作時,為了保證數據的一致性和正確性,我們需要添加事務管理機制進行管理。當對數據庫的數據進行操作失敗時,事務管理可以很好保證所有的數據回滾到原來的數據,如果操作成功,則保證所有需要更新的數據持久化。
例如:1.轉賬:A對B轉賬,需要先把A的錢減掉再把B的錢加上,這兩個操作任何一個失敗,都要撤銷整個轉賬過程,不然會出大問題。
2.向數據庫中插入訂單時,先插入訂單再插入訂單項,這兩個操作任何一個失敗都會影響數據的一致性,所以必須做事務的處理
3、Spring事務的配置
聲明式事務(不需要開啟注解代理等等)
配置通知(說明哪些方法需要攔截,被攔截的方法將應用配置好的事務屬性)
配置切入點需要對哪個類進行事務管理
注意:只會管理通知中有的那些方法
一. Spring支持編程式事務管理和聲明式事務管理兩種方式
編程式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對於編程式事務管理,spring推薦使用TransactionTemplate。
聲明式事務管理建立在AOP之上的。其本質是對方法前后進行攔截,然后在目標方法開始之前創建或者加入一個事務,在執行完目標方法之后根據執行情況提交或者回滾事務。聲明式事務最大的優點就是不需要通過編程的方式管理事務,這樣就不需要在業務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規則聲明(或通過基於@Transactional注解的方式),便可以將事務規則應用到業務邏輯中。
顯然聲明式事務管理要優於編程式事務管理,這正是spring倡導的非侵入式的開發方式。聲明式事務管理使業務代碼不受污染,一個普通的POJO對象,只要加上注解就可以獲得完全的事務支持。和編程式事務相比,聲明式事務唯一不足地方是,后者的最細粒度只能作用到方法級別,無法做到像編程式事務那樣可以作用到代碼塊級別。但是即便有這樣的需求,也存在很多變通的方法,比如,可以將需要進行事務管理的代碼塊獨立為方法等等。
聲明式事務管理也有兩種常用的方式,一種是基於tx和aop名字空間的xml配置文件,另一種就是基於@Transactional注解。顯然基於注解的方式更簡單易用,更清爽。但是個人推薦用xml配置文件的方式。
二. Spring事務特性
spring所有的事務管理策略類都繼承自org.springframework.transaction.PlatformTransactionManager接口
其中TransactionDefinition接口定義以下特性:
1.事務隔離級別
隔離級別是指若干個並發的事務之間的隔離程度。TransactionDefinition 接口中定義了五個表示隔離級別的常量:
TransactionDefinition.ISOLATION_DEFAULT:這是默認值,表示使用底層數據庫的默認隔離級別。對大部分數據庫而言,通常這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據。該級別不能防止臟讀,不可重復讀和幻讀,因此很少使用該隔離級別。比如PostgreSQL實際上並沒有此級別。
TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。該級別可以防止臟讀,這也是大多數情況下的推薦值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級別表示一個事務在整個過程中可以多次重復執行某個查詢,並且每次返回的記錄都相同。該級別可以防止臟讀和不可重復讀。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。
2.事務傳播行為
所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。在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。
3.事務超時
所謂事務超時,就是指一個事務所允許執行的最長時間,如果超過該時間限制但事務還沒有完成,則自動回滾事務。在 TransactionDefinition 中以 int 的值來表示超時時間,其單位是秒。
默認設置為底層事務系統的超時值,如果底層數據庫事務系統沒有設置超時值,那么就是none,沒有超時限制。
4.事務只讀屬性
只讀事務用於客戶代碼只讀但不修改數據的情形,只讀事務用於特定情景下的優化,比如使用Hibernate的時候。
默認為讀寫事務。
“只讀事務”並不是一個強制選項,它只是一個“暗示”,提示數據庫驅動程序和數據庫系統,這個事務並不包含更改數據的操作,那么JDBC驅動程序和數據庫就有可能根據這種情況對該事務進行一些特定的優化,比方說不安排相應的數據庫鎖,以減輕事務對數據庫的壓力,畢竟事務也是要消耗數據庫的資源的。
但是你非要在“只讀事務”里面修改數據,也並非不可以,只不過對於數據一致性的保護不像“讀寫事務”那樣保險而已。
因此,“只讀事務”僅僅是一個性能優化的推薦配置而已,並非強制你要這樣做不可
5.spring事務回滾規則
指示spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內拋出異常。spring事務管理器會捕捉任何未處理的異常,然后依據規則決定是否回滾拋出異常的事務。
默認配置下,spring只有在拋出的異常為運行時unchecked異常時才回滾該事務,也就是拋出的異常為RuntimeException的子類(Errors也會導致事務回滾),而拋出checked異常則不會導致事務回滾。可以明確的配置在拋出那些異常時回滾事務,包括checked異常。也可以明確定義那些異常拋出時不回滾事務。還可以編程性的通過setRollbackOnly()方法來指示一個事務必須回滾,在調用完setRollbackOnly()后你所能執行的唯一操作就是回滾。
三. 基於xml文件配置聲明式事務
(1)配置事務管理類

在spring的配置中配置數據源(dataSource)、事務管理器,事務管理器使用不同的orm框架事務管理器類就不同mybatis是org.springframework.jdbc.datasource.DataSourceTransactionManager。而hibernate事務管理器為org.springframework.orm.hibernate3.HibernateTransactionManager 。
(2)配置事務屬性

事務屬性在<tx:method>中進行設置,Spring支持對不同的方法設置不同的事務屬性,所以可以為一個<tx:advice>設置多個<tx:method>,其中name屬性指定匹配的方法(這里需要對這些方法名進行約定,如果事務切入點在service上,則最好和Dao的方法命名區分開,也不要使用get set關鍵字,防止和屬性的getter setter發生混淆)
事務有以下幾個常用屬性:
a.read-only:設置該事務中是否允許修改數據。(對於只執行查詢功能的事務,設置為TRUE可以提高事務的執行速度)
b.propagation:事務的傳播機制。一般設置為required。可以保證在事務中的代碼只在當前事務中運行,防止創建多個事務。
c.isolation:事務隔離級別。不是必須的。默認值是default。
d.timeout:允許事務運行的最長時間,以秒為單位。
e.rollback-for:觸發回滾的異常。
f.no-rollback-for:不會觸發回滾的異常。
***實際開發中,對於只執行查詢功能的事務,要設置read-only為TRUE,其他屬性一般使用默認值即可。
(3)配置事務的AOP切入點

該設置的含義是:對於org.sl.netmarket.services包及子包下的所有類的所有公共方法進行切入。(被切入的 方法經過<tx:method>篩選)web應用程序最合適的事務切入點是Service的方法上。
通過以上三個步驟設置好聲明式事務后,當Service中 的業務方法被調用之前,Spring會獲取事務對象並啟動事務。並使用try-catch-finally來處理異常。業務方法執行成功則會提交事務,默認情況下如果拋出了RuntimeException 或者Rrror 對象就會回滾事務。(注意: 這里注意一下,在tx:method中配置了rollback_for 中配置的Exception 這個是運行時的異常才會回滾不然其他異常是不會回滾的!)
這里示例一下:
1、數據訪問接口:

我這里定義了多個,我只示例一個就可以了。
2、dao接口的mapper映射文件:manager_mapper.xml

3、業務邏輯接口:

4、業務邏輯實現

5、mybatis 核心配置文件:netmk_mybatis_conf.xml

7、配置項目(重點)
spring核心配置文件:netmk_spring_config.xml



8、測試:

9、結果

也存到了數據庫中了的

四. 基於注解文件配置聲明式事務
1.在事務管理的dao實現類之前標注@Transactional
2.在要進行事務管理的方法前加上如@Transactional(propagation= Propagation.REQUIRED)
3.在配置文件中指定驅動:<tx:annotation-driven transaction-manager="transactionManager" />
示例:
@Transactional屬性

用法
@Transactional 可以作用於接口、接口方法、類以及類方法上。當作用於類上時,該類的所有 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該標注來覆蓋類級別的定義。
雖然 @Transactional 注解可以作用於接口、接口方法、類以及類方法上,但是 Spring 建議不要在接口或者接口方法上使用該注解,因為這只有在使用基於接口的代理時它才會生效。另外, @Transactional 注解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。如果你在 protected、private 或者默認可見性的方法上使用 @Transactional 注解,這將被忽略,也不會拋出任何異常。
默認情況下,只有來自外部的方法調用才會被AOP代理捕獲,也就是,類內部方法調用本類內部的其他方法並不會引起事務行為,即使被調用方法使用@Transactional注解進行修飾。
