事務的特性(ACID):
1. 原子性(Atomicity): 事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。
2. 一致性(Consistency): 事務前後數據的完整性必須保持一致
3. 隔離性(Isolation):一個事務的執行不能被其他事務干擾,即一個事務內部的操作及使用的數據對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。
4. 持久性(Durability):一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來的其他操作和數據庫故障不應該對其有任何影響。
在一個典型的應用中,併發是不可避免的,多個事務併發運行,操作同一個數據來完成任務。併發可能會導致以下問題:
1、髒讀(Dirty read):一個事務讀取了被另一個事務改寫但還未提交的數據時。如果這些數據被回滾,那麼之前的事務讀取的到數據就是無效的。
2、不可重複讀(Nonrepeatable read):在同一事務中,多次讀取同一數據返回的結果有所不同(讀到另一個事務提交的更新的數據)。
3、幻讀(Phantom read):一個事務讀取幾行記錄後,另一個事務插入了一些記錄(也可以刪除),幻讀就發生了。在後來的查詢中第一個事務就會發現有些原來沒有的記錄。
事務隔離級別:
1、讀未提交(READ_UNCOMMITED):允許讀取還未提交的改變了的數據。可能導致髒讀、幻讀、不可重複讀。
2、讀已提交(READ_COMMITED):允許在併發事務已經提交後讀取。可防止髒讀,但幻讀、不可重複讀仍可能發生。
3、可重複讀(REPEATABLE_READ):對相同字段的多次讀取是一致的,除非數據被事務本身改變。可防止髒讀、不可重複讀。但幻讀仍可能發生。
4、可串行化(SERIALIZABLE):完全服從ACID的隔離級別,確保不發生髒讀、幻讀和不可重複讀。他在所有的隔離級別中是最慢的,畢竟要完全鎖住在事務中涉及的數據表。
5、Default:使用了後端數據庫默認的隔離級別(spring中的選擇項,也是isolation屬性的默認值,Mysql默認採用REPEATABLE_READ隔離級別,Oracle默認採用READ_COMMITED隔離級別)。
再來個表格看的清楚些:
事務傳播行爲:
事務的傳播行爲是爲了解決業務層方法之間相互調用,產生的事務應該如何進行傳遞的問題。spring有如下7種傳播行爲:
1、PROPAGATION_REQUIRED:支持當前事務,如果當前不存在事務則新建一個。
2、PROPAGATION_SUPPORTS:支持當前事務,如果不存在,就不使用事務。
3、PROPAGATION_MANDATORY:支持當前事務,如果不存在,則拋出異常。
4、PROPAGATION_REQUIRES_NEW:如果當前有事務存在,掛起當前事務,創建一個新的事務。
5、PROPAGATION_NOT_SUPPORTED:以非事務方式運行,如果當前有事務存在,掛起當前事務。
6、PROPAGATION_NEVER:以非事務方式運行,如果當前有事務存在,拋出異常。
7、PROPAGATION_NESTED:如果當前存在一個事務,則該方法運行在一個嵌套的事務中。被嵌套的事務可以從當前事務中單獨的提交和回滾。如果當前不存在事務,則開始一個新的事務。各廠商對這種傳播行爲的支持參差不齊,使用時需注意。
可以看出1、2、3爲一組,都表現對當前事務的支持,不同的在於當前不存在事務的處理方式;4、5、6爲一組,都表現對當前事務的不支持,不同的在於當前有事務的處理方式。然後7單獨一組。
舉個小栗子,比如有一個service中有方法A,調用了方法B,方法B的傳播行爲是PROPAGATION_REQUIRED,那麼如果方法A的傳播行爲也是PROPAGATION_REQUIRED,方法A運行的時候,開啓了一個事務,方法A中執行到方法B的時候,察覺到當前已經有事務了,方法B就不會再創建新的事務,直接包含在方法A的事務當中。
隔離級別和傳播行爲在spring中的配置:
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="query*" read-only="true" propagation="SUPPORTS" /> <tx:method name="get*" read-only="true" propagation="SUPPORTS" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> </tx:attributes> </tx:advice>由於沒有給method配置isolation屬性,所以默認是isolation=‘DEFAULT’,也就是使用後端數據庫默認的隔離級別。