031_mysql事务的安全隐患
一. 事務(wù)的安全隱患
1. 讀的安全隱患
1.1. 臟讀: 一個(gè)事務(wù)讀到另外一個(gè)事務(wù)還未提交的數(shù)據(jù)。事務(wù)A讀取了事務(wù)B更新的數(shù)據(jù), 然后B回滾操作, 那么A讀取到的數(shù)據(jù)是臟數(shù)據(jù)。
1.2. 不可重復(fù)讀: 一個(gè)事務(wù)讀到了另外一個(gè)事務(wù)提交的數(shù)據(jù), 造成了前后兩次查詢(xún)結(jié)果不一致。事務(wù)A多次讀取同一數(shù)據(jù), 事務(wù)B在事務(wù)A多次讀取的過(guò)程中,對(duì)數(shù)據(jù)作了更新并提交, 導(dǎo)致事務(wù)A多次讀取同一數(shù)據(jù)時(shí), 結(jié)果不一致。
1.3. 幻讀: 一個(gè)事務(wù)讀到了另一個(gè)事務(wù)insert的數(shù)據(jù), 造成前后查詢(xún)結(jié)果不一致。系統(tǒng)管理員A將數(shù)據(jù)庫(kù)中所有學(xué)生的成績(jī)從具體分?jǐn)?shù)改為ABCDE等級(jí), 但是系統(tǒng)管理員B就在這個(gè)時(shí)候插入了一條具體分?jǐn)?shù)的記錄, 當(dāng)系統(tǒng)管理員A改結(jié)束后發(fā)現(xiàn)多出了一條記錄, 就好像發(fā)生了幻覺(jué)一樣, 這就叫幻讀。
1.4. 不可重復(fù)讀的和幻讀很容易混淆, 不可重復(fù)讀側(cè)重于修改, 幻讀側(cè)重于新增或刪除。解決不可重復(fù)讀的問(wèn)題只需鎖住滿足條件的行, 解決幻讀需要鎖表。
二. 事務(wù)的隔離級(jí)別
1. 查詢(xún)當(dāng)前的mysql8的默認(rèn)隔離級(jí)別。
2. 隔離級(jí)別第一級(jí)別: 讀未提交(read-uncommitted)
2.1. 打開(kāi)客戶(hù)端A, 先將事務(wù)的隔離級(jí)別設(shè)定為讀未提交, 并開(kāi)啟事務(wù)。
2.2. 客戶(hù)端A, 查詢(xún)用戶(hù)信息。
2.3. 客戶(hù)端A未提交事務(wù), 打開(kāi)客戶(hù)端B, 并開(kāi)啟事務(wù), 扣除客戶(hù)1的100塊錢(qián), 不提交事務(wù)。
2.4. 客戶(hù)端B未提交事務(wù), 客戶(hù)端A查看用戶(hù)信息, 查到了客戶(hù)端B更新的數(shù)據(jù)。
2.5. 客戶(hù)端B執(zhí)行了回滾操作, 那么客戶(hù)端A之前讀到的數(shù)據(jù)就是臟數(shù)據(jù)。
2.6. 此時(shí), 客戶(hù)端A減少客戶(hù)1的100塊錢(qián), 發(fā)現(xiàn)執(zhí)行前后, 客戶(hù)1都是900塊, 并沒(méi)有變成800塊。因?yàn)? 客戶(hù)端A讀到了客戶(hù)端B更新的數(shù)據(jù), 后來(lái)客戶(hù)端B又回滾了數(shù)據(jù), 客戶(hù)端A讀到了一條臟數(shù)據(jù)。
3. 讀已提交(第二級(jí)別 read-committed)
3.1. 讀已提交解決了臟讀問(wèn)題, 但是出現(xiàn)了不可重復(fù)讀問(wèn)題, 存在幻讀問(wèn)題。
3.2. 打開(kāi)客戶(hù)端A, 設(shè)置當(dāng)前的事務(wù)隔離級(jí)別為read committed(未提交讀), 開(kāi)啟事務(wù), 查詢(xún)表Account的所有記錄。
3.3. 打開(kāi)客戶(hù)端B, 開(kāi)啟事務(wù), 減少客戶(hù)1的100塊錢(qián), 未提交事務(wù)。
3.4. 客戶(hù)端A, 在客戶(hù)端B更新數(shù)據(jù)前后, 查詢(xún)的數(shù)據(jù)一樣, 解決了臟的問(wèn)題。
3.5. 客戶(hù)端B提交事務(wù)。
3.6. 客戶(hù)端A查詢(xún)到了客戶(hù)端B提交的數(shù)據(jù)。產(chǎn)生了不可重復(fù)讀的問(wèn)題, 客戶(hù)端A進(jìn)行同樣的2次查詢(xún), 2次查詢(xún)結(jié)果不一致。
4. 可重復(fù)讀(第三級(jí)別 repeatable read)
4.1. 打開(kāi)客戶(hù)端A, 設(shè)置當(dāng)前的事務(wù)隔離級(jí)別為repeatable read (可重復(fù)讀), 開(kāi)啟事務(wù), 查詢(xún)表Account的所有記錄。
4.2. 打開(kāi)客戶(hù)端B, 開(kāi)啟事務(wù), 扣除客戶(hù)1的100塊錢(qián), 未提交事務(wù)。
4.3. 客戶(hù)端B更新數(shù)據(jù), 未提交事務(wù), 查詢(xún)客戶(hù)端A, 客戶(hù)端B更新數(shù)據(jù)前后, 客戶(hù)端的數(shù)據(jù)不變, 解決了臟讀問(wèn)題。
4.4. 客戶(hù)端B提交事務(wù)。
4.5. 客戶(hù)端B提交事務(wù)后, 查詢(xún)客戶(hù)端A, 數(shù)據(jù)依然不變。
4.6. 客戶(hù)端B重新開(kāi)啟事務(wù), 插入一條數(shù)據(jù), 并且提交事務(wù)。
4.7. 客戶(hù)端B插入一條數(shù)據(jù), 并且提交事務(wù)后, 客戶(hù)端A查詢(xún)數(shù)據(jù), 依然是以前的數(shù)據(jù)。客戶(hù)端A提交事務(wù)后, 查詢(xún)出了最新數(shù)據(jù)。
5. 可串行化(第四級(jí)別 serializable)
5.1. 打開(kāi)客戶(hù)端A, 設(shè)置事務(wù)隔離級(jí)別為可串行化, 開(kāi)啟事務(wù), 查詢(xún)Account表。
5.2. 打開(kāi)客戶(hù)端B, 開(kāi)啟事務(wù), 查詢(xún)Account表, 客戶(hù)端B可以進(jìn)行查詢(xún)操作。
5.3. 在客戶(hù)端B, 執(zhí)行一個(gè)更新操作, 客戶(hù)端B卡住了, 如果此時(shí)客戶(hù)端A提交或回滾事務(wù), 客戶(hù)端B會(huì)更新成功; 如果客戶(hù)端A長(zhǎng)時(shí)間沒(méi)有提交或回滾事務(wù), 客戶(hù)端B的更新操作就超時(shí)報(bào)錯(cuò)。
5.4. 如果有一個(gè)連接的隔離級(jí)別設(shè)置為了串行化, 那么誰(shuí)先打開(kāi)了事務(wù), 就會(huì)在整張表上加了一個(gè)鎖, 其它事務(wù)不能進(jìn)行寫(xiě)操作。這種事務(wù)隔離級(jí)別解決了所有的安全問(wèn)題。但是這種隔離級(jí)別一般比較少用, 容易造成性能上的問(wèn)題, 效率比較低。
6.事務(wù)的隔離級(jí)別, 按效率劃分, 從高到低: 讀未提交-->讀已提交-->可重復(fù)讀-->可串行化。
7.事務(wù)的隔離級(jí)別, 按攔截程度, 從高到底: 可串行化-->可重復(fù)讀-->讀已提交-->讀未提交。
8. MySQL和Oracle默認(rèn)的事務(wù)隔離級(jí)別
8.1. MySQL默認(rèn)的事務(wù)隔離級(jí)別是: 可重復(fù)讀。
8.2. Oracle默認(rèn)的事務(wù)隔離級(jí)別是: 讀已提交。
9. 隔離級(jí)別
9.1. 讀未提交, 引發(fā)問(wèn)題臟讀。?
9.2. 讀已提交, 解決臟讀, 引發(fā)不可重復(fù)讀。
9.3. 可重復(fù)讀, 解決臟讀、不可重復(fù)讀、幻讀。
9.4. 可串行化, 解決臟讀、不可重復(fù)讀、幻讀, 同時(shí)似乎給整張表添加了一個(gè)鎖, 客戶(hù)并發(fā)讀, 但不能并發(fā)寫(xiě)。
10. 悲觀鎖(排它鎖)
10.1. 丟失更新
10.2. 悲觀鎖
10.3. 客戶(hù)端A開(kāi)啟事務(wù), 給用戶(hù)1的減少100塊, 沒(méi)有提交事務(wù)。
10.4. 客戶(hù)端B開(kāi)啟事務(wù), 刪除用戶(hù)1, 客戶(hù)端B卡頓了, 超時(shí)報(bào)錯(cuò)。
10.5. 客戶(hù)端A提交事務(wù)。
10.6. 客戶(hù)端B刪除用戶(hù)1成功。
總結(jié)
以上是生活随笔為你收集整理的031_mysql事务的安全隐患的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 020_MySQL运算符
- 下一篇: 003_Spring使用Slf4j和lo