一、事務特性
1.原子性
事務是一個原子操作單元,事務中包含的所有操作要么都做,要么都不做,沒有第三種情況。
2.一致性
事務操作前和操作后都必須滿足業務規則約束,比如說A向B轉賬,轉賬前和轉賬后AB兩個賬戶的總金額必須是一致的。
3.隔離性
隔離性是數據庫允許多個並發事務同時對數據進行讀寫的能力,隔離性可以防止事務並發執行時由於交叉執行導致數據不一致的問題。
4.持久性
事務完成后,對數據的修改是永久的,即使出現系統故障也不會丟失。
二、並發問題
1.更新丟失
當兩個事務選擇同一行,然后更新數據,由於每個事務都不知道其他事務的存在,就會發生丟失更新的問題,(你我同時讀取同一行數據,進行修改,你commit之后我也commit,那么我的結果將會覆蓋掉你的結果)。
2.臟讀
一個事務正在對一條記錄做修改,在這個事務提交之前,別的事務讀取到了這個事務修改之后的數據,也就是說,一個事務讀取到了其他事務還沒有提交的數據,就叫做臟讀。
3.不可重復讀
一個事務讀某條數據讀兩遍,讀到的是不一樣的數據,也就是說,一個事務在進行中讀取到了其他事務對舊數據的修改結果,(比如說 我開一個事務 修改某條數據 先查后改 執行修改動作的時候發現這條數據已經被別的事務刪掉了)
4.幻讀
一個事務中,讀取到了其他事務新增的數據,仿佛出現了幻象。(幻讀與不可重復讀類似,不可重復讀是讀到了其他事務update/delete的結果,幻讀是讀到了其他事務insert的結果)
三、隔離級別
1.未提交讀(read-uncommitted)
在一個事務中,可以讀取到其他事務未提交的數據變化,這種讀取其他會話還沒提交的事務,叫做臟讀現象,在生產環境中切勿使用。
2.已提交讀(read-committed)
在一個事務中,可以讀取到其他事務已經提交的數據變化,這種讀取也就叫做不可重復讀,因為兩次同樣的查詢可能會得到不一樣的結果。
3.可重復讀(repetable-read)
MySQL默認隔離級別,在一個事務中,直到事務結束前,都可以反復讀取到事務剛開始時看到的數據,並一直不會發生變化,避免了臟讀、不可重復讀現象,但是它還是無法解決幻讀問題。
4.可串行化(serializable)
這是最高的隔離級別,它強制事務串行執行,避免了前面說的幻讀現象,簡單來說,它會在讀取的每一行數據上都加鎖,所以可能會導致大量的超時和鎖爭用問題。
5.隔離級別一覽表
隔離級別 | 讀數據一致性 | 臟讀 | 不可重復讀 | 幻讀 |
未提交讀 | 最低級別,只保證不讀取物理上損壞的數據 | 有 | 有 | 有 |
已提交讀 | 語句級 | 無 | 有 | 有 |
可重復讀 | 事務級 | 無 | 無 | 有 |
可串行化 | 最高級別,事務級 | 無 | 無 | 無 |
隔離級別越嚴格,內部工作機制越復雜,較松散的隔離級別通常可以支持更高的並發。
四、個人分享
1.凡是涉及到表結構的語句,皆不受事務控制,嚴格的說,凡是DDL語句,都是自帶commit。比如create table 、alter table、truncate 等等
2.如果要確定出現了哪種並發問題,先查一下當前數據庫的隔離級別是什么,再進行判斷。
-- 查看當前數據庫的隔離級別 SHOW VARIABLES LIKE "%tx_isolation%"