面試官:談談你對mysql事務的認識?

偷懶了太久,給大家來補補文章。

引言

今天回頭繼續講講數據庫系列的文章。這篇文章屬於mysql數據庫系列,我們來談談事務方面的常見面試題。
那麼,具體題目有下面這些:
1、講講爲什麼用事務?事務的四大特性?事務的隔離級別知道吧,你們生產用哪種?
2、Innodb中ACID具體是如何實現的?
3、redo log和binlog的一致性如何保證?
4、大事務有哪些壞處?生產上遇到過大事務麼?你怎麼排查和解決的?
5、你有遇到過數據庫宕機重啓,事務丟失的情況麼?
6、可重複讀是怎麼實現的?

再三強調,每個問題都仔細看!都是高頻題!切勿遺漏!

正文

1、講講爲什麼用事務?事務的四大特性?事務的隔離級別知道吧,你們生產用哪種?
回答:爲什麼用事務?

這個問題從事務的四大特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability),這四個角度去答。例如原子性的角度,張三給李四轉賬,只有當張三賬戶的錢轉走了,並且李四賬戶的錢收到了之後轉賬事務才能提交。如果原子性無法保證,就會出現張三的錢轉走了,李四卻沒收到錢的情況!

Come on!這種easy回答,我就不一個個舉例了,過!

至於生產用哪種隔離級別?
Read Commited或者Repeatable都行,有道理即可。例如,我用了Read Commited,因爲這個隔離級別夠用了,用不上間隙鎖!詳情可以參照《互聯網項目中mysql應該選什麼事務隔離級別》這篇文章!

另外,額外記住Repeatable是默認的隔離級別即可!至於另外兩個隔離級別,Read uncommitted,一個事務能讀到另一個事務未提交的數據,隔離性都無法滿足,不用這個隔離級別。另外一個隔離級別Seriallzable,在這個隔離級別下,MVCC機制都無法滿足,數據庫併發性非常差,不用這個隔離級別。

ps:這個問題其實考察的是你對各個隔離級別的理解,所以務必牢記各個隔離級別的區別!

2、Innodb中ACID具體是如何實現的?
回答:老題了,詳細版,可以看這篇文章《程序員,知道Mysql中事務ACID的原理嗎?》
這裏給出簡單回答,

  • (1)利用undo log保證原子性

  • (2)利用redo log保證持久性

  • (3)利用鎖和MVCC機制保證隔離性

  • (4)通過原子性、持久性、隔離性來保證一致性

3、redo log和binlog的一致性如何保證?
回答:此題,先回憶一下redo log和binlog的區別!
redo log 記錄的是數據的物理變化,所以叫物理日誌,記錄的是是物理修改的內容(xxxx頁修改了xxx)。當我們修改數據的時候,寫完內存了,但數據還沒真正寫到磁盤的時候。此時我們的數據庫掛了,我們可以根據redo log來對數據進行恢復!

binlog 記錄的是數據的邏輯變化,所以又叫邏輯日誌,statement模式下記載的是update/delete/insert這樣的SQL語句,主要用來主從複製和恢復數據用。

這二者功能很像,都是用作”恢復“的!因此這二兩個日誌必須保證邏輯上一致,否則就會出現數據錯亂。例如,我們先寫redo log再寫binlog。在redo log寫完後,宕機了,此時binlog來不及寫。那麼重啓後,數據能夠根據redo log進行恢復,但是binlog沒記錄這個語句。那麼,我們在利用這個binlog恢復數據的時候,就會出現丟失數據的情形!

mysql怎麼解決的?
這裏考察的是mysql的內部XA事務!俗稱日誌的兩階段提交協議!
也就是說,將事務提交分爲了兩個階段,prepare階段和commit階段!

prepare:寫入redo log,並將回滾段置爲prepared狀態,此時binlog不做操作。

commit:innodb釋放鎖,釋放回滾段,設置提交狀態,寫入binlog,然後存儲引擎層提交。

mysql數據庫怎麼進行崩潰恢復的?
1> 崩潰恢復時,掃描最後一個Binlog文件,提取其中的xid;
2> InnoDB維持了狀態爲Prepare的事務鏈表,將這些事務的xid和binlog中記錄的xid做比較,如果在binlog中存在,則提交,否則回滾事務。

最後,這道題藍綠大廠,開水團,宇宙條都問過!

4、大事務有哪些壞處?生產上遇到過大事務麼?你怎麼排查和解決的?
回答:大事務,有的文章又稱之爲長事務,顧名思義,執行時間很長的事務!

至於壞處,例如事務執行時間太長,會造成大量的阻塞和鎖超時,容易造成主從延遲.另外,大事務如果執行失敗,回滾也會很耗時…(省略一千字)

怎麼排查?so easy!監控information_schema.Innodb_trx表,設置長事務閾值,超過就報警 / 或者 kill;

下面語句是查詢持續時間超過60s的事務

 select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60;

一般在生產中,會將監控大事務的語句,配成定時腳本,進行監控。

至於怎麼解決?結合業務場景,優化SQL,將一個大事務拆成多個小事務執行,或者縮短事務執行時間即可。

5、你有遇到過數據庫宕機重啓,事務丟失的情況麼?
回答:此題考查的是,sync_binlog配置(控制binlog刷盤時機)和innodb_flush_log_at_trx_commit配置(配置redolog刷盤時機)
由於這兩個配置的搭配組合很多種,一一舉例,太麻煩了,我隨意舉幾個例子
(1)innodb_flush_log_at_trx_commit=1 和 sync_binlog=0
這是mysql的默認配置,表示每次事務提交時都將 redo log 直接持久化到磁盤.但是MySQL不控制binlog的刷新,由操作系統自己控制它的緩存的刷新。

如果你答的是這套配置,那風險就是一旦系統宕機,在binlog_cache中的所有binlog信息都會被丟失。於是乎,你可以再結合上自己的公司背景來答。例如,我們公司規模不大,大家沒有技術沉澱,因此沒有修改過mysql的默認配置。但是,我私底下有過了解(突出自己勤奮好學),在該配置情況下,這兩個參數的值爲XXX,理論上操作系統宕機,有XXX的風險。但是,操作系統宕機的機率很低,因此我們也沒怎麼遇見過事務丟失的情況。

(2)innodb_flush_log_at_trx_commit=1 和 sync_binlog=1
很多文章提到的雙1配置。表示每次事務提交時都將redolog直接持久化到磁盤,binlog也會持久化到磁盤。

無疑,這個配置一致性最好,不會丟數據,但是性能是最差的。如果你答的是這套配置,你可以這麼答,我們系統涉及到一些金錢相關的業務邏輯,寧願慢,也不能一致性出錯,因此我們的配置爲XXX。至於性能問題,我們可以通過一些緩存,或者異步化設計進行改良。

(3)innodb_flush_log_at_trx_commit=2 和 sync_binlog=0
性能最好的一套配置,表示每次事務提交時,只是把redolog寫到OS cache,隔一秒,MySQL主動將OS cache中的數據批量fsync。而MySQL不控制binlog的刷新,由操作系統自己控制它的緩存的刷新。風險就是,操作系統一旦宕機,會丟數據。

這套配置下併發性最好。如果答這個配置,你可以說我們業務對併發的要求相對高一些,因此修改過XX參數。但是有操作系統宕機,丟數據的風險。但是,在實際環境中,操作系統崩潰的概率相比MySQL應用程序崩潰的概率,小很多…(自由發揮)

不一一舉例,言之有理即可!記住,全靠一張嘴,說得通就是你的!說不通,回去總結一下,換一家繼續說!無他,唯熟爾!

6、可重複讀是怎麼實現的?
回答:這道題坦白說,我不懂面試官想聽哪個角度的回答。我只能說一下我的理解,主要有以下兩個原因
(1)利用間隙鎖,防止幻讀的出現,保證了可重複讀
幻讀的問題存在是因爲新增或者更新操作,這時如果進行範圍查詢的時候(加鎖查詢),會出現不一致的問題,這時使用不同的行鎖已經沒有辦法滿足要求,需要對一定範圍內的數據進行加鎖。

(2)MVCC的快照生成時機不同
在可重複讀這個隔離級別下,遇到當事務中的第一個SELECT請求才創建read view,因此你是無法讀到其他事務提交的更改。而在讀已提交這個隔離級別下,每個SELECT都會獲取最新的read view,因此你能讀到其他事務提交的數據。

因爲,這個View生成時機不同,所以實現了可重複讀。
此題答案,有不同見解可以討論一下。反正我是沒懂,這一題究竟是想問什麼!

總結

OK,希望本文大家有所收穫!

本文其實對事務方面的問題沒講全,因爲在面試的時候通常會結合spring的事務和分佈式事務來問,例如什麼情況下spring事務會失效啊,巴拉巴拉。

但是將這兩塊內容都放在這個文章中,此文過長,因此回頭補上!希望大家多多關注!

本系列其他文章如下:
《面試官:講講mysql表設計要注意啥》
《面試官:談談對mysql索引的認識》
《面試官:談談你對mysql聯合索引的認識?》

未完待續…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章