MyISAM 不支援事務, innoDB支援事務
多個事務可能存在問題
在多個事務共同操作時容易出現這樣幾個問題:
- 髒讀(dirty read)
- 不可重複讀(nonrepeatable)
- 幻讀(phantom read)
來具體看一下這三個問題會有什麼影響
髒讀:A事務讀取到並使用了B事務還未提交的資料,這時如果B事務被撤回,則A操作的資料則是不準確的。比如以下銀行存取款例子:
A事務 | B事務 |
---|---|
開啟事務 | |
開啟事務 | |
查詢餘額為1000 | |
取出500,餘額變為500 | |
查詢餘額為500(髒資料) | |
撤銷事務,此時餘額為1000 | |
存入100,此時餘額為600 | |
提交事務 |
不可重複讀: A事務讀取了B事務已經提交的資料。同一個事務內查詢到不同的結果,比如A查詢到銀行賬戶有200元,然後準備取錢,這時B用同一個賬號將錢轉走,A取錢時會提示餘額不足,A在同一個事務內發現餘額發生了變化,第一次查到的結果不可重複
幻讀:解決了不可重複讀之後,保證同一個事務裡,查詢的結果都是事務開始時的狀態(一致性)。但是,如果另一個事務同時插入了新的資料,則本事務再次更新時,就會發現這些新插入的資料,好像之前讀到的不完整的資料是鬼影一樣幻覺
隔離級別
為了解決髒讀、不可重複讀、幻讀,有了"隔離級別這個概念"
SQL隔離級別包括:
- 讀未提交(read uncommitted):別人修改資料的事務還沒有提交,我在我的事務內也能讀到
- 讀可提交(read committed):別人修改資料的事務提交後,我在我的事務內才能讀到
- 可重複讀(repeatable read):別人修改資料的事務提交後我也讀不到,我只能讀到我事務開始時保持的資料狀態,我的事務內資料不受到其他事務的影響
- 序列化(serializable):我的事務還沒提交時,比我晚開始的事務只能是等待狀態,同時只能有一個事務在進行
比如我的賬戶有500元,按照時間順序執行以下兩個事務
A事務 | B事務 |
---|---|
啟動事務A查詢餘額為500 | |
啟動事務B查詢到餘額500 | |
存入100元 | |
再次查詢餘額Q1 | |
提交事務B | |
查詢餘額Q2 | |
提交事務A | |
再次查詢餘額Q3 |
根據不同的隔離級別,Q1、Q2、Q3會有不同的值。下面來詳細分析:
- 讀未提交(read uncommitted):能夠讀到其他事務未提交的資料,也就是B事務存入100雖然沒有提交,但是事務A第二次查詢餘額已經發生變化,Q1為600,後面沒有涉及到金額的變化,所以Q2/Q3的值也是600
- 讀可提交(read committed):能夠讀到其他事務已經提交的資料,查詢Q1時,因為B事務還沒有提交,所以並沒有影響到A事務,所以Q1的值還是500,當查詢Q2時,B事務已經提交,A事務可以讀到,所以Q2、Q3都是600
- 可重複讀(repeatable read):一個事務內的資料不受其他事務的影響,因此在A事務提交前,所以查到的餘額不變,同事務開始時的值是一樣的,因此Q1、Q2都為500。A事務提交後,可以發現B事務造成的資料影響,所以Q3的值為600
- 序列化(serializable):事務A開始後,事務B再發起,則會被鎖住,當事務A提交後,事務B才能進入,所以事務A提交前Q1、Q2的值是不變的都是500,提交事務A後,事務B才開始解鎖執行,B提交後,Q3查詢到的值為600
由以上可以看出這4種隔離級別,從上至下效能依次降低,安全性依次提高。
事務的啟動方式
事務有兩種啟動方式:
- 顯式啟動事務語句,begin或者start transaction,提交commit,回滾rollback
- set autocommit=0,該命令會把這個執行緒的自動提交關掉。這樣只要執行一個select語句,事務就啟動,並不會自動提交,直到主動執行commit或rollback或斷開連線。
本文為極客時間《MySQL實戰45講》的學習筆記,其中含有部分原文,如有侵權行為請聯絡我立刻刪除
第二節:MySQL系列之一條更新SQL的生命歷程