ACID,是指在可靠數據庫管理系統(DBMS)中,事務(transaction)所應該具有的四個特性:
A:原子性(Atomicity):事務是一個或多個行為捆綁在一起組成一個單獨的工作單元,事務中的動作要不都發生,要不都不發生.
C:一致性(Consistent):即在事務開始之前和結束之后,數據庫的完整性約束沒有被破壞.
數據庫層面:在一個事務執行前和執行后,數據會符合你設置的約束(例如unique約束,foreign key約束,check約束等)和觸發器設置.由數據庫進行保證.
業務層面:保持業務的一致性.需要由開發人員進行保證.
I:隔離性(Isolation):指的是在並發環境中,事務之間互相影響的程度(即並發事務間數據的可見程度).當不同的事務同時操縱相同的數據時,每個事務都有各自的完整數據空間.由並發事務所做的修改必須與任何其他並發事務所做的修改隔離.事務查看數據更新時,數據所處的狀態要么是另一事務修改它之前的狀態,要么是另一事務修改它之后的狀態,事務不會查看到中間狀態的數據.
D:持久性(Durability):一旦事務完成,事務的結果應該持久化,用來保證即使系統崩潰也不會破壞事務的結果.
我們通過可視化界面對不同的數據庫進行管理,不可避免要實現多個進程訪問數據庫同一數據,或者修改同一數據。不得不提到數據庫利用加鎖和阻塞來保證事物之間不同等級的隔離性,從而實現事務的互不干擾的訪問和操作數據庫.
干擾數據的隔離性的四大問題:
No.1 丟失修改(丟失更新 ps:反正叫什么的都有)
如果兩個事務都要更新數據庫一個字段X,X=100;
事務A | 事務B |
讀取X=100 | 讀取X=100 |
寫入x=X+100 | 寫入x=X+200 |
事務結束x=200 | 事務結束x=300 |
最后x=300 |
兩個不同的事務同時獲得了相同的數據,又都對這個數據進行了修改,那么先提交的事務的更新就會被后提交事務的更新覆蓋掉.叫做丟失更新.
No.2 臟讀(讀臟數據 未提交讀)
事務A | 事務B |
寫入x=X+100 (x=200) | |
讀取X=200 (讀取了事務B未提交的數據) | |
事務回滾x=100 | |
事務結束x=100 | |
事務結束 |
事務讀取了未提交的數據,如圖 事務B可能出現未提交或者提交不成功的情況而進行回滾,這就導致事務A讀取了錯誤的數據,也叫臟數據.
No.3 不可重復讀
一個事務執行期間,在自己沒有更新數據庫的情況下,同一個查詢操作在執行一次或多次的情況下,結果應該是一致的.
事務A | 事務B |
讀取X=100 | 讀取X=100 |
讀取X=100 | 寫入x=X+100 |
事務結束, x=200 | |
讀取X=200 (此時,在同一個事務A中,讀取的X值發生了變化!) |
|
事務結束 | |
這種情況事務A多次讀取數據出現不一致的結果.
摘自薩師煊老師的數據庫系統概論的解釋:不可重復讀包括三種情況(這里列舉第一種情況 因為后兩種情況也稱為幻影現象):
(1):事務T1讀取某一數據之后,事務T2對其進行了修改,當事務T1再次讀該數據時,得到與前一次不同的值.如上所示
No.4 幻讀(幻影現象)
這個問題可有意思了,很多博主說他跟不可重復讀有相似的地方,我認為這樣更容易讓讀者混淆.數據庫書中說的幻影現象就是不可重復讀情況中的兩種.
(2):事務T1按一定條件從數據庫中讀取了某些數據記錄后,事務T2刪除了其中部分記錄,當T1再次按照相同條件讀取數據時,發現某些記錄神秘的消失了.
(3):事務T1按一定條件從數據庫中讀取了某些數據記錄后,事務T2插入了一些記錄,當T1再次按照相同條件讀取數據時,發現多了一些記錄.
知乎大佬的例子:
users: id 主鍵
1、T1:select * from users where id = 1;
2、T2:insert into `users`(`id`, `name`) values (1, 'big cat');
3、T1:insert into `users`(`id`, `name`) values (1, 'big cat');
T1 :主事務,檢測表中是否有 id 為 1 的記錄,沒有則插入,這是我們期望的正常業務邏輯。
T2 :干擾事務,目的在於擾亂 T1 的正常的事務執行。
在 RR(這里摘自知乎某位大佬的回答 我也不曉得RR是什么東東) 隔離級別下,1、2 是會正常執行的,3 則會報錯主鍵沖突,對於 T1 的業務來說是執行失敗的,這里 T1 就是發生了幻讀,因為T1讀取的數據狀態並不能支持他的下一步的業務,見鬼了一樣。
所以 mysql 的幻讀並非什么讀取兩次返回結果集不同,而是事務在插入事先檢測不存在的記錄時,驚奇的發現這些數據已經存在了,之前的檢測讀獲取到的數據如同鬼影一般
這里要靈活的理解讀取的意思,第一次select是讀取,第二次的 insert 其實也屬於隱式的讀取,只不過是在 mysql 的機制中讀取的,插入數據也是要先讀取一下有沒有主鍵沖突才能決定是否執行插入。
不可重復讀側重表達 讀-讀,幻讀則是說 讀-寫,用寫來證實讀的是鬼影。
鏈接:https://www.zhihu.com/question/47007926/answer/222348887
來源:知乎
在標准SQL規范中,定義了4個事務隔離級別,不同的隔離級別對事務的處理不同:
A. 未授權讀取(Read uncommited):允許臟讀取,但不允許丟失修改。
對應一級封鎖協議:一級封鎖協議是:事務T在修改數據R之前必須先對其加X鎖,直到事務結束才釋放。事務結束包括正常結束(COMMIT)和非正常結束(ROLLBACK)。
B. 授權讀取(Read Committed):允許不可重復讀取,但不允許臟讀取和丟失修改。這可以通過“瞬間共享讀鎖”和“排他寫鎖”實現。
對應二級封鎖協議:二級封鎖協議是:一級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,讀完后即可釋放S鎖(瞬間S鎖)。
C. 可重復讀取(Repeatable Read):禁止不可重復讀取和臟讀取和丟失修改,但是有時可能出現幻影數據。這可以通過“共享讀鎖”和“排他寫鎖”實現。
對應三級封鎖協議:三級封鎖協議是:一級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,直到事務結束才釋放。
D. 序列化(Serializable):提供嚴格的事務隔離。它要求事務序列化執行,事務只能一個接着一個地執行,但不能並發執行。
四級封鎖協議是對三級封鎖協議的增強,其實現機制也最為簡單,直接對事務中所讀取或者更改的數據所在的表加表鎖,也就是說,其他事務不能讀寫該表中的任何數據。這樣所有的臟讀,不可重復讀,幻讀,都得以避免!
我真是日了 好多博客連一級封鎖協議都不一樣哈 有加排他鎖的,有加共享鎖的. 我就是按照書上的加排他鎖吧.
並發控制有四個問題,也有五個問題的......
我就按照我的這想法吧 畢竟說法那么多 P313附近有這個知識點.有疑問就去查