如何理解事務
概念:一組業務邏輯,注意,是一組。例如,A轉錢給B A就要有更新語句,B也要有更新語句,這兩個一起纔是一個事務。
事務ACID
automatic:原子性,
每個事務是獨立的個體,要麼成功,要麼失敗
consitency:一致性,
例如某個事務是實現A向B轉100元,則A賬戶減100元,B賬戶增加100元,體現一致性
isolation:隔離性,
併發時事務之間不能相互干擾
- read uncomitted:
讀未提交,級別最低,B事務併發讀取到A事務爲提交的數據,這會出現髒讀
- read comitted:
讀提交(oracle默認),顧名思義,B事務操作要等A事務操作完成後進行,但是這樣會出現不可重複讀問題,即當A事務提交前查看的記錄和提交後的記錄不一致
- repeatable read
可重複讀(Mysql默認),開始在讀取事務開啓的時候不允許進行修改操作,但這樣不能阻止發生插入操作,這樣會出現虛讀(幻讀),即在查看事務提交時發生insert,莫名其妙發現數據不一致。
- Serializable 是最高的事務隔離級別
,單事務,兩個事務同時對一個內容進行操作時,必須等前一個事務提交成功後再執行下一個事務,在該級別下,事務串行化順序執行,*可以避免髒讀、不可重複讀與幻讀*。但是這種事務隔離級別效率低下,比較耗數據庫性能,一般不使用。
duriblity:持久性,
即事務提交發生後,對改變的數據是永久性的
數據庫數據丟失更新問題
概念:
後一次的更新內容將前一次未提交的數據覆蓋了
形象解釋:第一次開啓事務A,減去金額100元,事務未提交或者其他原因,同時事務B查詢數據庫還是1000元,然後增加100元,B修改後發現是1100,元,這就是造成前一次的更新丟失
解決辦法:
- 樂觀鎖:
樂觀認爲不會出現鎖獲取失敗問題,即先進行業務判斷,不得已到更新最後一步去拿鎖。
實現思路如下:一般在需要修改加鎖的字段上增加版本號或者時間戳或者先查詢後修改。
原理:樂觀鎖是否在事務中其實都是無所謂的,其底層機制是這樣:在數據庫內部update同一行的時候是不允許併發的,即數據庫每次執行一條update語句時會獲取被update行的寫鎖,直到這一行被成功更新後才釋放。因此在業務操作進行前獲取需要鎖的數據的當前版本號,然後實際更新數據時再次對比版本號確認與之前獲取的相同,並更新版本號,即可確認這之間沒有發生併發的修改。如果更新失敗即可認爲老版本的數據已經被併發修改掉而不存在了,此時認爲獲取鎖失敗,需要回滾整個業務操作並可根據需要重試整個過程。
- 悲觀鎖:
先加鎖,再進行業務操作,即“悲觀”認爲更新鎖會失敗,所以要在業務之前先成功獲取鎖的控制,即“一鎖二查三業務”。
分類:排他鎖和共享鎖
- 排他鎖:
只能一個進行寫,不能擁有其他鎖,也就是說,若事務T對數據對象A加上X鎖,則只允許T讀取和修改A,其他任何事務都不能再對A加任何類型的鎖,直到T釋放A上的鎖。這就保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A
- 共享鎖:只能讀不能寫
實現:通常來講在數據庫上的悲觀鎖需要數據庫本身提供支持,即通過常用的select … for update操作來實現悲觀鎖。當數據庫執行select for
update時會獲取被select中的數據行的行鎖,因此其他併發執行的select for
update如果試圖選中同一行則會發生排斥(需要等待行鎖被釋放),因此達到鎖的效果。select for
update獲取的行鎖會在當前事務結束時自動釋放,因此必須在事務中使用。注意:不同的數據庫對select for update的實現和支持都是有所區別的,例如oracle支持select for update no wait,表示如果拿不到鎖立刻報錯,而不是等待,mysql就沒有no
wait這個選項。另外mysql還有個問題是select for
update語句執行中所有掃描過的行都會被鎖上,這一點很容易造成問題。因此如果在mysql中用悲觀鎖務必要確定走了索引,而不是全表掃描。
springAOP事務傳播行爲
一個業務A,一個業務B,AB如何共享事務,不同傳播行爲共享方案不同。
詳解:
什麼意思呢?比如業務A爲銀行轉賬的業務。
業務B爲轉完賬發短信的業務,平常我們是轉完錢,那麼我們就需要收到短信說我們的賬戶上被轉走多少錢,而收錢的那一方則需要收到短信說賬戶被轉進多少錢,那麼這兩個業務是使用同一個事務呢?還是分別使用不同的事務,也就是如果是使用同一個事務的話,我們轉錢成功了代表業務A成功了,但是業務B發送短信時出現問題,則說明該事務失敗,那麼剛纔轉的錢就算不成功,需要回滾,但是實際生活中,是不能這樣的,轉錢成功了,短信沒發送成功,那麼短信在重新發送一次即可。不需要讓業務A重新在操作一遍。這就是業務A和業務B共享事務的解決方法,讓他們兩個使用各自的事務。而傳播行爲就是提供這樣的共享方案的屬性。
傳播行爲方案
1.PROPAGATION_REQUIRED ,required ,必須使用事務 (默認值)
A 如果使用事務,B 使用同一個事務。(支持當前事務)
A 如果沒有事務,B將創建一個新事務。
2.PROPAGATION_SUPPORTS,supports ,支持事務
A 如果使用事務,B 使用同一個事務。(支持當前事務)
A 如果沒有事務,B 將以非事務執行。
3.PROPAGATION_MANDATORY,mandatory 強制
A 如果使用事務,B 使用同一個事務。(支持當前事務)
A 如果沒有事務,B 拋異常
4.PROPAGATION_REQUIRES_NEW , requires_new ,必須是新事務
A 如果使用事務,B將A的事務掛起,再創建新的。
A 如果沒有事務,B將創建一個新事務
5.PROPAGATION_NOT_SUPPORTED ,not_supported 不支持事務
A 如果使用事務,B將A的事務掛起,以非事務執行
A 如果沒有事務,B 以非事務執行
6.PROPAGATION_NEVER,never 從不使用
A 如果使用事務,B 拋異常
A 如果沒有事務,B 以非事務執行
7.PROPAGATION_NESTED nested 嵌套
A 如果使用事務,B將採用嵌套事務。
嵌套事務底層使用Savepoint
設置保存點,將一個事務,相當於拆分多個。比如業務A爲AB兩個曹祖,業務B爲CD兩個操作,業務AB使用同一個事務,在AB (POINT)
CD,當業務B失敗時,回滾到POINT處,從而業務A還是成功的,就是保持點的操作。 底層使用嵌套try方式
掌握:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
總結
參考鏈接:
http://www.cnblogs.com/whgk/p/6638192.html
http://www.cnblogs.com/ws-astrologer/p/6681089.html
http://blog.csdn.net/qq_33290787/article/details/51924963