数据库 - 事务管理(ACID)隔离级别 事务传播行为
轉載自? ?數據庫 - 事務管理(ACID)隔離級別 事務傳播行為
總覽:
事務的4大特性(ACID)
原子性(Atomicity)
原子性是指事務包含的所有操作要么全部成功,要么全部失敗回滾,這和前面兩篇博客介紹事務的功能是一樣的概念,因此事務的操作如果成功就必須要完全應用到數據庫,如果操作失敗則不能對數據庫有任何影響。
一致性(Consistency)
一致性是指事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之后都必須處于一致性狀態。
拿轉賬來說,假設用戶A和用戶B兩者的錢加起來一共是5000,那么不管A和B之間如何轉賬,轉幾次賬,事務結束后兩個用戶的錢相加起來應該還得是5000,這就是事務的一致性。
隔離性(Isolation)
隔離性是當多個用戶并發訪問數據庫時,比如操作同一張表時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作所干擾,多個并發事務之間要相互隔離。
即要達到這么一種效果:對于任意兩個并發的事務T1和T2,在事務T1看來,T2要么在T1開始之前就已經結束,要么在T1結束之后才開始,這樣每個事務都感覺不到有其他事務在并發地執行。
關于事務的隔離性數據庫提供了多種隔離級別,稍后會介紹到。
持久性(Durability)
持久性是指一個事務一旦被提交了,那么對數據庫中的數據的改變就是永久性的,即便是在數據庫系統遇到故障的情況下也不會丟失提交事務的操作。
事務并發訪問的問題(隔離性)
臟讀
兩個事務正在并發的執行,事實上最后結果應該是1500才對,時間5時刻的查詢余額為0就是臟數據,事務A讀取了事務B中未提交的數據,這就是臟讀。
| 1 | 開始事務 | - |
| 2 | - | 開始事務 |
| 3 | - | 查詢余額有1000 |
| 4 | - | 取出1000,余額0 |
| 5 | 查詢余額0 | - |
| 6 | - | 撤銷掉事務 |
| 7 | 存入500,余額500 | - |
| 8 | 提交事務 | - |
不可重復讀
兩個事務正在并發的執行,結果A兩次讀取的結果不一樣,這是因為兩次查詢有間隔,期間被其他事務修改并提交了事務,相比臟讀的區別是,不可重復讀是讀取另一事務提交的數據。這種現象也是正常的,是由于事務的隔離級造成的,但是在在某些特別的情況下也是不允許的。
| 1 | 開始事務 | - |
| 2 | - | 開始事務 |
| 3 | - | 查詢余額有1000 |
| 4 | 查詢余額1000 | - |
| 5 | ? | 取出1000,余額0 |
| 6 | - | 提交事務 |
| 7 | 查詢余額0 | - |
幻讀
兩個事務正在并發的執行,事務A第一次統計和第二統計的結果不一樣,是因為事務B新增了一條數據,和不可重復讀一樣,都是讀取了另外一個事務的數據,不同的是不可重復讀查詢的是同一條數據,而幻讀則是針對批量的數據,或者說不可重復讀是A讀取了B的更新數據,幻讀是A讀取了B的新增數據。
| 1 | 開始事務 | - |
| 2 | - | 開始事務 |
| 3 | 統計總金額10000 | - |
| 4 | - | - |
| 5 | ? | 存入100 |
| 6 | - | 提交事務 |
| 7 | 統計總金額10100 | - |
數據庫的隔離級別(MySQL為例)
明白上面的問題之后就明白為什么需要隔離級別了,不同的隔離級別能處理不同的并發事務問題,下表:
| READ_UNCOMMITTED | 允許 | 允許 | 允許 |
| READ_COMMITTED | 禁止 | 允許 | 允許 |
| REPEATABLE_READ | 禁止 | 禁止 | 允許 |
| SERIALIZABLE | 禁止 | 禁止 | 禁止 |
MySQL默認的事務級別是READ_COMMITTED
JDBC的數據隔離級別設置
| TRANSACTION_READ_UNCOMMITTED | ur | 就是俗稱“臟讀”(dirty read),在沒有提交數據時能夠讀到已經更新的數據 |
| TRANSACTION_READ_COMMITTED | cs | 在一個事務中進行查詢時,允許讀取提交前的數據,數據提交后,當前查詢就可以讀取到數據。update數據時候并不鎖住表 |
| TRANSACTION_REPEATABLE_READ | rs | 在一個事務中進行查詢時,不允許讀取其他事務update的數據,允許讀取到其他事務提交的新增數據 |
| TRANSACTION_SERIALIZABLE | rr | 在一個事務中進行查詢時,不允許任何對這個查詢表的數據修改。 |
Spring的事務傳播行為
事務傳播
事務怎么傳播?方法A傳播到方法B。
Spring解決的就是方法之間的事務傳播。
下面看下每一種行為具體代表的含義:
REQUIRED
業務方法需要在一個事務中運行。如果方法運行時,已經處在一個事務中,那么這個時候就會加入到該事務中,如果當前沒有事務環境的話,就會為自己創建一個新的事務。
SUPPORTS
這一事務屬性表明,如果業務方法A在某個事務范圍內被調用,則方法成為事務的一部分。如果業務方法在事務范圍外被調用,則方法在沒有事務的環境下執行。即當標注了事務傳播屬性——SUPPORTS的業務方法在另一個bean的業務方法中執行時,如果另一個bean的業務方法開啟了事務,它就會處在事務中執行,如果另一個bean的業務方法也沒開啟事務,那么它也在沒有事務的環境中進行。
MANDATORY
該屬性指定業務方法只能在一個已經存在的事務中執行,業務方法不能發起自己的事務。如果業務方法在沒有事務的環境下調用,容器就會拋出異常。一種比較強硬的方式。
REQUIRES_NEW
該屬性表明不管當前是否存在事務,業務方法總會為自己發起一個新的事務。如果方法已經運行在一個事務中,則原有事務會被掛起,新的事務會被創建,直到方法執行結束,新事務才算結束,原先的事務才會恢復執行。
NOT_SUPPORTED
聲明方法不需要事務。如果方法沒有關聯到一個事務,容器不會為它開啟事務。如果方法在一個事務中被調用(在其他業務bean的方法中被調用了,而其他業務bean的方法是開啟了事務的),該事務會被掛起,在方法調用結束后,原先的事務便會恢復執行。
NEVER
指定業務方法絕對不能在事務范圍內執行。如果業務方法在某個事務中執行,容器會拋出異常,只有業務方法沒有關聯到任何事務,才能正常執行。比較強硬的方式,就是不支持事務。
NESTED
(嵌套事務)如果一個活動的事務存在,則當前方法運行在一個嵌套的事務中。 如果沒有活動事務,就創建一個新的事務。它使用了一個單獨的事務,這個事務擁有多個可以回滾的保存點。內部事務的回滾不會對外部事務造成影響。外部事務回滾會導致內部事務的回滾。如果被調用的內部方法沒有捕獲異常,跑出異常也會導致外部事務的回滾。
看下Spring中枚舉定義的7種事務傳播行為
package org.springframework.transaction.annotation;public enum Propagation {REQUIRED(0),SUPPORTS(1),MANDATORY(2),REQUIRES_NEW(3),NOT_SUPPORTED(4),NEVER(5),NESTED(6);private final int value;private Propagation(int value) {this.value = value;}public int value() {return this.value;} }在使用注解方式的事務時候我們可以用下面的方式來設置事務的傳播行為
@Transactional(propagation?= Propagation.REQUIRED)是不是很方便。
只讀事務
readOnly屬性:設置為只讀事務,對于只讀事務,它就不能進行更新操作,一般只存在數據讀取的時候,可以將readOnly屬性設置為true,可提供效率。
事務超時
timeout屬性:代表事務的超時時間,默認為30s,一般情況下都不需要設置超時時間。如果超過時間就回滾。
總結
以上是生活随笔為你收集整理的数据库 - 事务管理(ACID)隔离级别 事务传播行为的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 维修尘封已久的坏电脑竟然花了我350元电
- 下一篇: MySQL instr()函数