1. 事務基本概念mysql
事務是指在數據庫系統執行過程當中的一個邏輯單元,由有限的數據庫操做序列構成。spring
1.1 事務的基本特色sql
事務具備四個屬性:ACID本別是: 原子性(atomicity)、一致性(consistency)、隔離性(isolation)、持久性(durability)。數據庫
原子性(要麼成功要麼失敗):一個事務是不可分割的基本單位,事務中的全部操做要麼要麼所有都作,要麼所有不作。併發
一致性(數據庫狀態變化):事務必須使數據庫從一個狀態變化到另外一個狀態。一致性與原子性密切相關。oracle
隔離性(互不影響):一個事務的執行不能被其餘事務干擾。不一樣的事務之間互補干擾。性能
持久性(不能撤銷):一個事務一旦提交,它對數據庫中數據的改變就是永久性的。atom
2. 事務的基本原理url
spring事務的本質是對數據庫事務的支持,沒有數據庫事務的支持,spring是沒法提供事務功能的。spa
對jdbc操做數據庫要使用事務,使用以下步驟:
(1) 獲取鏈接 Connection con = DriverManager.getConnection(url,username,password);
(2) 開啓事務 con.setAutoCommit(false);
(3) 執行數據庫curd操做
(4) 提交事務/回滾事務 con.commit()/con.rollback();
(5) 關閉鏈接 conn.close();
在是用spring的事務管理功能後,咱們能夠不用再寫2和4的代碼,而是由spring自動完成, 具體如何自動完成的,使用到了aop和動態代理的相關技術。
3. spring事務的傳播特性
spring事務的傳播特性就是定義同時存在多個事務的時候,spring應該如何處理這些事務的行爲。
這些屬性定義在TransactionDefinition中,具體常量解釋以下:
常量名稱 | 常量解釋 |
PROPAGATION_REQUIRED | 支持當前事務,若是當前沒有事務就新建一個事務。這是最多見的選擇,也是spring默認的事務的傳播 |
PROPAGATION_REQUIRES_NEW | 新建事務,若是當前存在事務,就把當前事務掛起。新建的事務和被掛起的事務是兩個獨立的事務,外層事務失敗回滾以後不能回滾內部事務執行的結果, 內存事務失敗拋出異常,外層事務捕獲,也能夠不處理回滾操做。 |
PROPAGATION_SUPPORTS | 支持當前事務,若是當前沒有事務,就以非事務的方式運行 |
PROPAGATION_NOT_SUPPORTED | 以非事務的方式運行,若是當前存在事務,就把當前事務掛起 |
PROPAGATION_MANDATORY | 支持當前事務,若是當前沒有事務,就拋出異常 |
PROPAGATION_NEVER | 以非事務的方式運行,若是當前存在事務,就拋出異常 |
PROPAGATION_NESTED | 若是一個活動的事務存在,則運行在嵌套的事務中,若是沒有活動的事務,則按PROPAGATION_REQUIRED執行。使用一個單獨的事務,這個事務擁有多個能夠回滾的事務保存點。 |
4. 數據庫事務隔離級別
髒讀: 在一個事務中讀取到另外一個事務未提交的數據。
不可重複度:在一個事務中兩次的查詢結果不同(針對update操做)。
幻讀:在一個事務中兩次的查詢結果不同(正對insert操做)
√ 可能出現 × 不會出現 | |||
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
ISOLATION_READ_UNCOMMITED | √ | √ | √ |
ISOLATION_READ_COMMITED | × | √ | √ |
ISOLATION_REPEATABLE_READ | × | × | √ |
ISOLATION_SERIALIZABLE | × | × | × |
ISOLATION_READ_UNCOMMITED:事務最低的隔離級別,它容許另一個事務看到當前事務未提交的數據。可能產生藏獨、不可重複度、幻讀。
ISOLATION_READ_COMMITED:另外一個事務不能讀取當前事務未提交的數據。
ISOLATION_REPEATABLE_READ:防止了髒讀、不可重複讀出現,可是可能出現幻讀。
ISOLATION_SERIALIZABLE:防止了髒讀、不可重複讀、幻讀,可靠性最好的事務級別,可是執行效率也是最慢的,慎用。
數據庫隔離級別越高,越能保證數據的完整性和一致性,可是對併發性能的影響也越大。多數數據的默認隔離級別都是read commited,如sqlServer,oracle;少數數據庫隔離級別默認是repeatable read,如mysqlInnoDB。
5. spring中的事務隔離級別
ISOLATION_DEFAULT | spring默認的隔離級別,使用數據庫默認的隔離級別 |
ISOLATION_READ_UNCOMMITED | 同數據庫事務隔離級別 |
ISLATION_READ_COMMITED | 同數據庫事務隔離級別 |
ISOLATION_REPEATABLE_READ | 同數據庫事務隔離級別 |
ISOLATION_SERIALIZEABLE | 同數據庫事務隔離級別 |
6. 舉例說明事務的嵌套,理解spring事務傳播機制
假設外層事務serviceA的methodA()方法調用內層的serviceB的methodB()方法
PROPAGATION_REQUIRED
若是serviceB.methodB()的事務定義爲PROPAGATION_REQUIRED,若是servieA.methodA()執行的時候已經開啓了事務,那麼serviceB.methodB()在執行的時候發現已經在methodA的事務中,那麼就不會再新建一個事務;若是methodA()沒有在事務中,那麼methodB()在執行的時候就會新建一個事務。這樣在methodA()和methodB()中的任何地方出現異常,事務都會回滾,即便被methodA中catch住,也會由於是一個事物在methodB的時候標記爲事物失敗而拋出一個UnexpectedRollbackException(org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only)致使回滾。
PROPAGATION_REQUIRES_NEW
執行到method()的時候,methodA()所在的事務就會掛起,methodB()會新開啓一個事務,methodB()所在的事務執行完之後method所在的事務纔會繼續執行。它與PROPAGATION_REQUIRED的區別在於回滾的程度。由於B是新起的一個事務,若是B已經提交,A失敗回滾,那麼B也是不會回滾; 若是B失敗回滾,拋出的異常被A捕獲(try catch住),若是在catch中沒有拋出異常,那麼A不會回滾;若是catch中拋出異常而且是A上rollbackFor設置的異常,則回滾,若是不是,則不會回滾。
serviceA#methodA() -> serviceB#methodB()
若是methodB() 拋出異常,在methodA()中try catch住,若是沒有從新拋出或者拋出的異常不是methodA方法rollbackFor設置的異常,那麼 methodA 不會滾,methodB回滾;
若是methodB()拋出異常,在methodA()中try catch住,而且從新拋出了methodA上rollbackFor設置的異常,那麼methodA回滾,methodB回滾;
若是methodB()拋出異常,在methodA()中沒有try catch住,那麼methodA methodB都會回滾;
若是隻有methodA拋出異常,那麼methodA回滾,methodB不會滾
PROPAGATION_NESTED
serviceA#methodA() -> serviceB#methodB()
若是methodB()拋出異常,若是在methodA中catch處理,那麼methodA不會滾,methodB回滾;若是methodA沒有catch處理,那麼methodA,methodB都回滾
若是methodA()拋出異常,那麼methodA,methodB都回滾。
7. 對於同一個類中事物方法調用失效的狀況處理
首先須要設置exposeProxy=true, 經過xml方式或者註解方式:<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true" /> 或者 @EnableAspectJAutoProxy(exposeProxy=true)
調用:((UserService)AopContext.currentProxy()).testExpose1();