四大特性(ACID)
1.原子性(Atomicity)
原子性是指事務包含的所有操作要么全部成功,要么全部失敗回滾。失敗回滾的操作事務,將不能對事務有任何影響。
2. 一致性(Consistency)
一致性是指事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之后都必須處於一致性狀態。
例如:A和B進行轉賬操作,A有200塊錢,B有300塊錢;當A轉了100塊錢給B之后,他們2個人的總額還是500塊錢,不會改變。
3. 隔離性(Isolation)
隔離性是指當多個用戶並發訪問數據庫時,比如同時訪問一張表,數據庫每一個用戶開啟的事務,不能被其他事務所做的操作干擾(也就是事務之間的隔離),多個並發事務之間,應當相互隔離。
例如同時有T1和T2兩個並發事務,從T1角度來看,T2要不在T1執行之前就已經結束,要么在T1執行完成后才開始。將多個事務隔離開,每個事務都不能訪問到其他事務操作過程中的狀態;就好比上鎖操作,只有一個事務做完了,另外一個事務才能執行。
4. 持久性(Durability)
持久性是指事務的操作,一旦提交,對於數據庫中數據的改變是永久性的,即使數據庫發生故障也不能丟失已提交事務所完成的改變。
事務的隔離級別
事務的隔離級別從低到高分別是:讀未提交,讀已提交,可重復讀,串行化,這四個隔離級別可以分別解決臟讀,不可重復讀,幻讀的問題。
先介紹一下不存在事務隔離級別的時候會出現的情況
很明顯的看出,旺財對A添加的20塊不翼而飛了,這就是“數據丟失”,對事務不加任何鎖(不存在事務隔離),就會導致這種問題。
讀未提交
操作:寫數據的時候添加一個X鎖(排他鎖),也就是在寫數據的時候不允許其他事務進行寫操作,但是讀不受限制,讀不加鎖。
這樣就可以解決了多個人一起寫數據而導致了“數據丟失”的問題,但是會引發新的問題——臟讀。
臟讀:讀取了別人未提交的數據。
因而引入了另外一個事務隔離級別——讀已提交
讀已提交
操作:寫數據的時候加上X鎖(排他鎖),讀數據的時候添加S鎖(共享鎖),而且有約定:如果一個數據加了X鎖就沒法加S鎖;同理如果加了S鎖就沒法加X鎖,但是一個數據可以同時存在多個S鎖(因為只是讀數據),並且規定S鎖讀取數據,一旦讀取完成就立刻釋放S鎖(不管后續是否還有很多其他的操作,只要是讀取了S鎖的數據后,就立刻釋放S鎖)。
這樣就解決了臟讀的問題,但是又有新的問題出現——不可重復讀。
不可重復讀:同一個事務對數據的多次讀取的結果不一致。
解決方法——引入隔離級別更高事務隔離:可重復讀
可重復讀
操作:對S鎖進行修改,之前的S鎖是:讀取了數據之后就立刻釋放S鎖,現在修改是:在讀取數據的時候加上S鎖,但是要直到事務准備提交了才釋放該S鎖,X鎖還是一致。
這樣就解決了不可重復讀的問題了,但是又有新的問題出現——幻讀。
例如:
有一次旺財對一個“學生表”進行操作,選取了年齡是18歲的所有行, 用X鎖鎖住, 並且做了修改。
改完以后旺財再次選擇所有年齡是18歲的行, 想做一個確認, 沒想到有一行竟然沒有修改!
這是怎么回事? 出了幻覺嗎?
原來就在旺財查詢並修改的的時候, 小強也對學生表進行操作, 他插入了一個新的行,其中的年齡也是18歲! 雖然兩個人的修改都沒有問題, 互不影響, 但從最終效果看, 還是出了事。
(碼農翻身注: 正是小強的操作, 讓旺財出現了“幻讀”)
解決幻讀的方式——串行化
串行化
事務只能一件一件的進行,不能並發進行。
總結:
mysql默認的隔離級別是:可重復讀。
oracle中只支持2個隔離級別:讀已提交和串行化,默認是讀已提交。
擴展一些關於范式的的總結:
第一范式:一個單元格只存儲一個值。
第二范式:滿足所有的屬性字段唯一依賴主鍵
第三范式:消除傳遞依賴,例如:訂單號----決定----->用戶id------決定------>用戶名;這個時候我們就需要消除這種依賴傳遞;但是又時候也得兼顧查詢效率,高查詢率低修改率的字段可以考慮違反第三范式。
參考:劉欣《碼農翻身》中的數據庫村的旺財和小強