面試總結:關于MySQL事務的10個問題常見面試問答(FQA)
學習關系型資料庫MySQL是很好的切入點,大部分人工作中用慣了CRUD,對面試官刨根問底的靈魂拷問你還能對答如流嗎?我們有必要了解一些更深層次的資料庫基礎原理。
文章每周持續更新,各位的「三連」是對我最大的肯定。可以微信搜尋公衆号「 後端技術學堂 」第一時間閱讀(一般比部落格早更新一到兩篇)
整理了面試中,關于MySQL事務和存儲引擎10個FAQ(Frequently asked questions),你想知道的都在這裡。
什麼是事務?
事務就是「一組原子性的SQL查詢」,或者說一個獨立的工作單元。如果資料庫引擎能夠成功地對資料庫應用該組查詢的全部語句,那麼就執行該組查詢。如果其中有任何一條語句因為崩潰或其他原因無法執行,那麼所有的語句都不會執行。也就是說,事務内的語句,要麼全部執行成功,要麼全部執行失敗。
事務控制文法知道嗎?
BEGIN 或 START TRANSACTION 顯式地開啟一個事務;
COMMIT / COMMIT WORK二者是等價的。送出事務,并使已對資料庫進行的所有修改成為永久性的;
ROLLBACK / ROLLBACK WORK。復原會結束使用者的事務,并撤銷正在進行的所有未送出的修改;
SAVEPOINT identifier 在事務中建立一個儲存點,一個事務中可以有多個 SAVEPOINT;
RELEASE SAVEPOINT identifier 删除一個事務的儲存點;
ROLLBACK TO identifier 把事務復原到标記點;
SET TRANSACTION 用來設定事務的隔離級别。InnoDB 存儲引擎提供事務的隔離級别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE
用通俗的語言說說你了解的事務
用銀行業務舉個栗子,使用者lemon有兩銀行卡,一張是招商銀行CMBC的工資卡,另一張是工商銀行ICBC的儲蓄卡,每月5号發工資都要把招行卡的100萬轉到建設銀行儲蓄卡賬戶。記住這裡的銀行縮寫後面就是對應的資料表名稱,你要記不住,我給你理一理。
招商銀行(CMBC):“存麼?白癡!”
中國工商銀行(ICBC): “愛存不存!”
中國建設銀行(CCB): “存?存不?”
中國銀行(BC): “不存!”
中國農業銀行(ABC): “啊,不存!”
民生銀行(CMSB):“存麼?SB!"
興業銀行(CIB):“存一百。”
國家開發銀行(CDB):“存點吧!”
彙豐銀行(HSBC):“還是不存!”
這個轉賬的操作可以簡化抽成一個事務,包含如下步驟:
查詢CMBC賬戶的餘額是否大于100萬
從CMBC賬戶餘額中減去100萬
在ICBC賬戶餘額中增加100萬
以下語句對應建立了一個轉賬事務:
START TRANSACTION;
SELECT balance FROM CMBC WHERE username='lemon';
UPDATE CMBC SET balance = balance - 1000000.00 WHERE username = 'lemon';
UPDATE ICBC SET balance = balance + 1000000.00 WHERE username = 'lemon';
COMMIT;
事務的ACID特性是什麼?
ACID其實是事務特性的英文首字母縮寫,具體的含義是這樣的:
原子性(atomicity)
一個事務必須被視為一個不可分割的最小工作單元,整個事務中的所有操作要麼全部送出成功,要麼全部失敗復原,對于一個事務來說,不可能隻執行其中的一部分操作。
緻性(consistency)
資料庫總是從一個一緻性的狀态轉換到另外一個一緻性的狀态。在前面的例子中,一緻性確定了,即使在執行第三、四條語句之間時系統崩潰,CMBC賬戶中也不會損失100萬,不然lemon要哭死因為事務最終沒有送出,是以事務中所做的修改也不會儲存到資料庫中。
隔離性(isolation)
通常來說,一個事務所做的修改在最終送出以前,對其他事務是不可見的。在前面的例子中,當執行完第三條語句、第四條語句還未開始時,此時如果有其他人也準備給lemon的CMBC賬戶存錢,那他看到的CMBC賬戶裡還是有100萬的。
持久性(durability)
一旦事務送出,則其所做的修改就會永久儲存到資料庫中。此時即使系統崩潰,修改的資料也不會丢失。持久性是個有點模糊的概念,因為實際上持久性也分很多不同的級别。有些持久性政策能夠提供非常強的安全保障,而有些則未必。而且「不可能有能做到100%的持久性保證的政策」否則還需要備份做什麼。
什麼是髒讀、不可重複讀、幻讀?
髒讀
在事務A修改資料之後送出資料之前,這時另一個事務B來讀取資料,如果不加控制,事務B讀取到A修改過資料,之後A又對資料做了修改再送出,則B讀到的資料是髒資料,此過程稱為髒讀Dirty Read。
不可重複讀
一個事務内在讀取某些資料後的某個時間,再次讀取以前讀過的資料,卻發現其讀出的資料已經發生了變更、或者某些記錄已經被删除了。
幻讀
事務A在按查詢條件讀取某個範圍的記錄時,事務B又在該範圍内插入了新的滿足條件的記錄,當事務A再次按條件查詢記錄時,會産生新的滿足條件的記錄(幻行 Phantom Row)
不可重複讀與幻讀有什麼差別?
不可重複讀的重點是修改:在同一事務中,同樣的條件,第一次讀的資料和第二次讀的「資料不一樣」。(因為中間有其他事務送出了修改)
幻讀的重點在于新增或者删除:在同一事務中,同樣的條件,第一次和第二次讀出來的「記錄數不一樣」。(因為中間有其他事務送出了插入/删除)
SQL的四個隔離級别知道嗎?具體是什麼解決了什麼問題說說看
SQL實作了四個标準的隔離級别,每一種級别都規定了一個事務中所做的修改,哪些在事務内和事務間是可見的,哪些是不可見的。低級别的隔離級一般支援更高的并發處理,并擁有更低的系統開銷。
各個隔離級别可以不同程度的解決髒讀、不可重複讀、幻讀。隔離級别各有所長,沒有完美的解決方案,脫離業務場景談具體實施都是耍流氓。
MySQL中哪些存儲引擎支援事務?
MySQL中InnoDB和NDB Cluster存儲引擎提供了事務處理能力,以及其他支援事務的第三引擎。
什麼是自動送出?
MySQL預設采用自動送出AUTOCOMMIT模式。也就是說,如果不是顯式地開始一個事務,則每個查詢都被當作一個事務執行送出操作。
對于MyISAM或者記憶體表這些事務型的表,修改AUTOCOMMIT不會有任何影響。對這類表來說,沒有COMMIT或者ROLLBACK的概念,也可以說是相當于一直處于AUTOCOMMIT啟用的模式。
在事務中可以混合使用存儲引擎嗎?
盡量不要再同一個事務中使用多種存儲引擎,MySQL伺服器層不管理事務,事務是由下層的存儲引擎實作的。
如果在事務中混合使用了事務型和非事務型的表(例如InnoDB和MyISAM表),在正常送出的情況下不會有什麼問題。
但如果該事務需要復原,非事務型的表上的變更就無法撤銷,這會導緻資料庫處于不一緻的狀态,這種情況很難修複,事務的最終結果将無法确定。是以,為每張表選擇合适的存儲引擎非常重要。
MySQL存儲引擎類型有哪些?
最常用的存儲引擎是InnoDB引擎和MyISAM存儲引擎,InnoDB是MySQL的預設事務引擎。
檢視資料庫表目前支援的引擎 :
show table status from 'your_db_name' where name='your_table_name';
查詢結果表中的
Engine
字段訓示存儲引擎類型。
InnoDB存儲引擎的特點和應用場景?
InnoDB是MySQL的預設「事務引擎」,被設定用來處理大量短期(short-lived)事務,短期事務大部分情況是正常送出的,很少會復原。
更多InnoDB事務模型相關,參考MySQL官方手冊,這裡貼一下連結:
https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-model.html曆史
現代MySQL版本中的InnoDB在曆史上叫InnoDB plugin,這個MySQL插件在2008年被開發出來,直到2010在Oracle收購了Sun公司後,釋出的MySQL5.5才正式使用InnoDB plugin替代了舊版本的InnoDB,至此 「備胎」成功轉正成為MySQL的禦用引擎而不再是插件,你看一個插件都這麼努力。
特點
采用多版本并發控制(MVCC,MultiVersion Concurrency Control)來支援高并發。并且實作了四個标準的隔離級别,通過間隙鎖next-key locking政策防止幻讀的出現。
引擎的表基于聚簇索引建立,聚簇索引對主鍵查詢有很高的性能。不過它的二級索引secondary index非主鍵索引中必須包含主鍵列,是以如果主鍵列很大的話,其他的所有索引都會很大。是以,若表上的索引較多的話,主鍵應當盡可能的小。另外InnoDB的存儲格式是平台獨立。
InnoDB做了很多優化,比如:磁盤讀取資料方式采用的可預測性預讀、自動在記憶體中建立hash索引以加速讀操作的自适應哈希索引(adaptive hash index),以及能夠加速插入操作的插入緩沖區(insert buffer)等。
InnoDB通過一些機制和工具支援真正的熱備份,MySQL的其他存儲引擎不支援熱備份,要擷取一緻性視圖需要停止對所有表的寫入,而在讀寫混合場景中,停止寫入可能也意味着停止讀取。
MyISAM存儲引擎的特點和應用場景?
MyISAM是MySQL 5.1及之前的版本的預設的存儲引擎。MyISAM提供了大量的特性,包括全文索引、壓縮、空間函數(GIS)等,但MyISAM不「支援事務和行級鎖」,對于隻讀資料,或者表比較小、可以容忍修複操作,依然可以使用它。
特性
MyISAM「不支援行級鎖而是對整張表加鎖」。讀取時會對需要讀到的所有表加共享鎖,寫入時則對表加排它鎖。但在表有讀取操作的同時,也可以往表中插入新的記錄,這被稱為并發插入。
MyISAM表可以手工或者自動執行檢查和修複操作。但是和事務恢複以及崩潰恢複不同,可能導緻一些「資料丢失」,而且修複操作是非常慢的。
對于MyISAM表,即使是BLOB和TEXT等長字段,也可以基于其前500個字元建立索引,MyISAM也支援「全文索引」,這是一種基于分詞建立的索引,可以支援複雜的查詢。
如果指定了DELAY_KEY_WRITE選項,在每次修改執行完成時,不會立即将修改的索引資料寫入磁盤,而是會寫到記憶體中的鍵緩沖區,隻有在清理鍵緩沖區或者關閉表的時候才會将對應的索引塊寫入磁盤。這種方式可以極大的提升寫入性能,但是在資料庫或者主機崩潰時會造成「索引損壞」,需要執行修複操作。
InnoDB與MyISAM對比
說了這麼多估計看一眼也沒記住,給你一張表,簡單羅列兩種引擎的主要差別,如下圖。
其他存儲引擎
MySQL還支援其他一些存儲引擎,比如memory引擎、NDB叢集引擎、CSV引擎,由于這些引擎沒有上述InnoDB 和MyISAM 常用,這裡不作介紹,感興趣可以去翻MySQL文檔了解。這裡同樣給出官方連結:
https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html再說兩句
這一篇是MySQL基礎篇,我力求用通俗易懂和圖表結合的形式給大家梳理這塊知識,越是基礎和底層的知識越容易被考察掌握程度,以上知識點都可能成為面試中的一個考察點,相信看完對MySQL事務和存儲引擎應該有一個比較完整的了解。
最後,感謝各位的閱讀,文章的目的是分享對知識的了解,若文中出現明顯纰漏也歡迎指出,我們一起在探讨中學習。
原文位址
https://www.cnblogs.com/NanoDragon/p/12650049.html