誰家面試往死里問事務?。?/h1>
大家好,我是哪吒。
說個挺奇葩的事,有個老鐵給我發(fā)私信吐槽了一下他的面試經(jīng)歷,他去了個國企單位面試,然后面試官跟他就MySQL事務的問題聊了半個多小時。
面試嘛這些都不稀奇,總能遇到是千奇百怪的人,千奇百怪的問題。不過,我分析這個面試官一定是在事務這塊吃過虧,哈哈哈!
下面通過十六張圖詳解一下MySQL事務,事無巨細。
下次聊一個小時都沒問題~
一、引入
事務,指的是一組操作的集合,它是一個不可分割的工作單位,它會把這個集合中所有的操作作為一個整體一起向系統(tǒng)提交或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。
事務常常用于在需要操作多條記錄或多張表的情況下,為了避免在執(zhí)行過程中出現(xiàn)異常行為導致數(shù)據(jù)一致性被破壞,這時候我們就需要開啟事務。
就比如最經(jīng)典的銀行轉賬問題:
張三給李四轉賬1000塊錢,張三銀行賬戶的余額減少1000,而李四銀行賬戶的余額要增加 1000。
這一組操作就必須在一個事務的范圍內(nèi),即要么都成功,要么都失敗。總不可能在出現(xiàn)異常后,張三的余額減少了,李四的余額卻沒有增加?
假設我們沒有開啟事務,也就是這一系列操作不在一個事務的范圍內(nèi):
- 這是我們的理想情況。
假設拋出了異常。
為了解決上述的問題,我們就需要通過開啟事務來完成,只需要在業(yè)務邏輯執(zhí)行之前開啟事務,執(zhí)行完畢后必須提交事務,如果執(zhí)行過程中報錯,則回滾事務,把數(shù)據(jù)恢復到事務開始之前的狀態(tài)。
值得一提的是,默認MySQL的事務是自動提交的,也就是說,當執(zhí)行完一條DML語句時,MySQL會立即隱式的提交事務。
即默認情況下,一條SQL語句就是一個事務。假如關閉自動提交則必須在每次執(zhí)行SQL之后手動提交事務,否則SQL不生效。
二、事務操作
1、查看事務提交方式
SELECT @@autocommit;
其中 1 表示自動提交事務,0表示手動提交事務。
2、設置事務提交方式
SET @@autocommit = 0; # 設置為手動提交事務
SET @@autocommit = 1; # 設置為自動提交事務
3、提交事務
COMMIT;
上述我們把事務的提交方式修改為了手動提交,接下來我們來驗證一下“關閉自動提交事務則必須在每次執(zhí)行SQL之后手動提交事務,否則SQL不生效”。
我們關閉了自動提交事務,執(zhí)行SQL后發(fā)現(xiàn)執(zhí)行成功,但沒有提交事務,查看數(shù)據(jù)庫發(fā)現(xiàn)數(shù)據(jù)并未發(fā)生變化。
待我們提交事務后,數(shù)據(jù)才更新!
4、回滾事務
ROLLBACK;
當我們執(zhí)行事務的過程中碰到了異常導致中止,可以使用rollback
使得事務回滾,即恢復事務開始執(zhí)行之前的狀態(tài)。
5、開啟事務
START TRANSACTION; 或 BEGIN;
我們除了可以以關閉自動提交事務,然后手動commit的方式控制事務以外,還可以通過在SQL開始執(zhí)行之前,先執(zhí)行START TRANSACTION; 或 BEGIN;然后執(zhí)行SQL,最后commit的方式控制事務。
三、四大特性
事務有著四大特性(ACID):
原子性(Atomicity):事務是不可分割的最小操作單元,要么全部成功,要么全部失敗。
- 一致性(Consistency):事務完成時,必須使所有的數(shù)據(jù)都保持一致狀態(tài)。
- 隔離性(Isolation):數(shù)據(jù)庫系統(tǒng)提供的隔離機制,保證事務在不受外部并發(fā)操作影響的獨立 環(huán)境下運行。
持久性(Durability):事務一旦提交或回滾,它對數(shù)據(jù)庫中的數(shù)據(jù)的改變就是永久的。
四、并發(fā)事務問題
多個事務同時操作某一個數(shù)據(jù)庫或者某一張表時,可能會產(chǎn)生一系列問題:
- 贓讀:一個事務讀到另外一個事務還沒有提交的數(shù)據(jù)
不可重復讀:一個事務先后讀取同一條記錄,但兩次讀取的數(shù)據(jù)不同,稱之為不可重復讀。
幻讀:一個事務按照條件查詢數(shù)據(jù)時,沒有對應的數(shù)據(jù)行,但是在插入數(shù)據(jù)時,又發(fā)現(xiàn)這行數(shù)據(jù)已經(jīng)存在,好像出現(xiàn)了 "幻影"。
五、事務的隔離級別
為了解決并發(fā)事務所引發(fā)的問題,在數(shù)據(jù)庫中引入了事務隔離級別。主要有以下幾種:
隔離級別(發(fā)生- √,不發(fā)生- ×) | 臟讀 | 不可重復讀 | 幻讀 |
Read uncommitted(讀未提交) | √ | √ | √ |
Read committed(讀已提交) | × | √ | √ |
Repeatable Read(可重復讀)(默認) | × | × | √ |
Serializable (串行化) | × | × | × |
MySQL默認的隔離級別為Repeatable Read,也就是只會產(chǎn)生幻讀問題。當然,隨著安全系數(shù)的增加,數(shù)據(jù)庫的性能也有所下降。
- 查看事務隔離級別。
SELECT @@TRANSACTION_ISOLATION;
- 設置事務隔離級別。
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE }