小滴课堂MySQL相关面试题总结
個人博客文章地址:小滴課堂MySQL相關面試題總結
1. MySQL事務的ACID是什么?
考察點:事務的4個特征
- 原子性Atomicity:
- 一個事務必須是不可分割的最小工作單元,整個事務操作要么全部成功,要么全部失敗,一般就是通過commit和rollback來控制;
- 一致性Consistency:
- 事務必須是使數(shù)據(jù)庫從一個一致性狀態(tài)變到另一個一致性狀態(tài)。通俗的來說就是,事務的結果必須和預期相符(參考文章:什么是事務的一致性?)
- 隔離性Isolation:
- 一個事務相對于另一個事務是隔離的,一個事務所做的修改是在最終提交以前,對其他事務是不可見的,一個事務對一個數(shù)據(jù)進行操作時,其他事務不允許對同一個數(shù)據(jù)進行操作;
- 持久性Durability:
- 事務一旦提交,則其所做的修改就會永久保存到數(shù)據(jù)庫中。此時即使系統(tǒng)崩潰,修改的數(shù)據(jù)也不會丟失;
2. MySQL中的臟讀、幻讀、不可重復讀度你知道多少?
考察點:事務的隔離級別以及導致的相關問題
- 臟讀:如果某個事務對數(shù)據(jù)的修改尚未提交時,其他某個事務也能讀取到該數(shù)據(jù),導致一個事務可以讀到另一個事務未提交的數(shù)據(jù)內(nèi)容稱為臟讀!
- 幻讀:如果當前事務讀取某一個范圍內(nèi)的記錄時,另一個事務又在該范圍內(nèi)插入新記錄,導致當前事務再次讀取該范圍的記錄時,兩次結果不一樣,稱為幻讀!
- 不可重復讀:如果同一個事務前后多次讀取某個數(shù)據(jù)內(nèi)容,不能讀取到相同的結果,(中間有另一個事務也操作了該數(shù)據(jù)),這種情況稱為不可成復讀!
幻讀和不可重復度的區(qū)別:
- 前者是一個范圍,后者是本身數(shù)據(jù)內(nèi)容,從總的結果來看,兩者都表現(xiàn)為兩次讀取的結果不一致!
3. 事務隔離級別由低到高有哪幾種?MySQL默認是哪種?
考察點:事務的隔離級別、MySQL的事務隔離級別
-
事務的隔離級別:由低到高(未提交讀 => 提交讀 => 可重復讀 => 可串行化)
-
未提交讀(Read Uncommitted):讀取未提交內(nèi)容,事務中的修改即使沒有提交,其他事務也能讀取,事務可以讀到為提交的數(shù)據(jù)稱為臟讀, 也存在不可重復讀、幻讀問題!
-- 臟讀例子: -- 運營小姐姐配置了一個付費課程活動,原價500元的課程,配置成50元,但是事務沒提交。這時,你剛好看到這個課程那么便宜準備購買,但是運營小姐姐馬上回滾了事務,重新配置并提交了事務,你準備下單的時候發(fā)現(xiàn)價格變回了500元 -
提交讀(Read Committed):讀取提交內(nèi)容,一個事務開始后只能看見已經(jīng)提交的事務所做的修改,在事務中執(zhí)行兩次同樣的查詢可能得到不一樣的結果,也叫做不可重復讀(前后多次讀取,不能讀到相同的數(shù)據(jù)內(nèi)容),也存在幻讀問題!
-- 不可重復度例子: -- 老王在小滴課堂有1000積分,準備去兌換《面試專題課程》,查詢數(shù)據(jù)庫確實有1000積分,但是老王的女友同時也在別的地方登錄,把1000積分兌換了《SpringCloud微服務專題課程》,且在老王之前提交事務;當系統(tǒng)幫老王兌換《面試專題課程》時發(fā)現(xiàn)積分預計沒了,兌換失敗。-- 老王事務A事先讀取了數(shù)據(jù),他女友事務B緊接了更新了數(shù)據(jù)且提交了事務,事務A再次讀取該數(shù)據(jù)時,數(shù)據(jù)已經(jīng)發(fā)生了改變! -
可重復讀(Repeatable Read):mysql默認的事務隔離級別,解決臟讀、不可重復讀的問題,存在幻讀問題。
幻讀問題:MySQL的InnoDB引擎通過MVCC自動幫我們解決,即多版本并發(fā)控制!
-- 幻讀例子: -- 老王在小滴課堂有1000積分,準備去兌換《面試專題課程》,查詢數(shù)據(jù)庫確實有1000積分,老王的女友同時也在別的地方登錄先兌換了這個《面試專題課程》,老王的事務提交的時候發(fā)現(xiàn)提示購買的課程已經(jīng)存在了,之前讀取的沒用了,像是幻覺。 -
可串行化(Serializable):解決臟讀、不可重復讀、幻讀,可保證事務安全,但強制所有事務串行執(zhí)行(即,一個事務執(zhí)行,其他事務需要排隊等待),所以并發(fā)效率低!
-
4. MySQL如何解決不可重復度和幻讀問題?
-
不可重復讀:針對于修改同一條數(shù)據(jù),會出現(xiàn)前后不一致的情況。解決方式為添加行鎖
-
幻讀:針對于一批數(shù)據(jù),主要體現(xiàn)在新增和刪除操作。解決幻讀需要鎖整張表
參考文章1:https://blog.csdn.net/nhlbengbeng/article/details/84951613
參考文章2:https://blog.csdn.net/sanyuesan0000/article/details/90235335
對于MVCC,在《高性能MySQL》中有如下解釋:
4.1 MySQL解決不可重復讀問題
-- MySQL中,默認使用的事務隔離界別是可重復讀,為了解決不可重復讀問題,InnoDB采用了MVCC(多版本并發(fā)控制)【基于樂觀鎖】來解決! -- MVCC(多版本并發(fā)控制)是利用在每條數(shù)據(jù)后面加了隱藏的兩列(創(chuàng)建版本號和刪除版本號),每個事務在開始的時候都會有一個**遞增的當前事務版本號**!-- MVCC新增 begin; -- 假設獲取的 當前事務版本號=1 insert into user (id,name,age) values (1,"張三",10); -- 新增,當前事務版本號是1 insert into user (id,name,age) values (2,"李四",12); -- 新增,當前事務版本號是1 commit; -- 提交事務| 1 | 張三 | 10 | 1 | NULL |
| 2 | 李四 | 12 | 1 | NULL |
| 1 | 張三 | 10 | 1 | NULL |
| 2 | 李四 | 12 | 1 | 3 |
| 1 | 張三 | 10 | 1 | 10 |
| 2 | 李四 | 12 | 1 | 3 |
| 1 | 張三 | 11 | 10 | NULL |
查詢操作為了避免查詢到舊數(shù)據(jù)或已經(jīng)被其他事務更改過的數(shù)據(jù),需要滿足如下條件:
1、查詢時當前事務的版本號需要大于或等于創(chuàng)建版本號create_version
2、查詢時當前事務的版本號需要小于刪除的版本號delete_version,或者當前刪除版本號delete_version=NULL
即:(create_version <= current_version < delete_version) || (create_version <= current_version && delete_version-=NULL) ,這樣就可以避免查詢到其他事務修改的數(shù)據(jù),同一個事務中,實現(xiàn)了可重復讀!
執(zhí)行結果應該是:
| 1 | 張三 | 11 | 10 | NULL |
4.2 MySQL解決幻讀問題
什么是幻讀,如下:
InnoDB實現(xiàn)的RR通過mvcc機制避免了這種幻讀現(xiàn)象
快照讀和當前讀
讓數(shù)據(jù)變得可重復讀,但我們讀到的數(shù)據(jù)可能是歷史數(shù)據(jù),不是數(shù)據(jù)庫最新的數(shù)據(jù)。這種讀取歷史數(shù)據(jù)的方式,我們叫它快照讀 (snapshot read),而讀取數(shù)據(jù)庫最新版本數(shù)據(jù)的方式,叫當前讀 (current read)。
快照讀介紹
當執(zhí)行select操作時,innodb默認會執(zhí)行快照讀,會記錄下這次select后的結果,之后select 的時候就會返回這次快照的數(shù)據(jù),即使其他事務提交了也不會影響當前select的數(shù)據(jù),這就實現(xiàn)了可重復讀了。
快照的生成當在第一次執(zhí)行select的時候,也就是說假設當A開啟了事務,然后沒有執(zhí)行任何操作,這時候B insert了一條數(shù)據(jù)然后commit,這時候A執(zhí)行 select,那么返回的數(shù)據(jù)中就會有B添加的那條數(shù)據(jù)。之后無論再有其他事務commit都沒有關系,因為快照已經(jīng)生成了,后面的select都是根據(jù)快照來的。
當前讀
對于會對數(shù)據(jù)修改的操作(update、insert、delete)都是采用當前讀的模式。在執(zhí)行這幾個操作時會讀取最新的版本號記錄,寫操作后把版本號改為了當前事務的版本號,所以即使是別的事務提交的數(shù)據(jù)也可以查詢到。假設要update一條記錄,但是在另一個事務中已經(jīng)delete掉這條數(shù)據(jù)并且commit了,如果update就會產(chǎn)生沖突,所以在update的時候需要知道最新的數(shù)據(jù)。也正是因為這樣所以才導致幻讀。
- 在快照讀情況下,mysql通過mvcc來避免幻讀。
- 在當前讀情況下,mysql通過X鎖或next-key來避免其他事務修改:
- 使用串行化讀的隔離級別
- (update、delete)當where條件為主鍵時,通過對主鍵索引加record locks(索引加鎖/行鎖)處理幻讀
- (update、delete)當where條件為非主鍵時,通過next-key鎖處理。next-key是record locks(索引加鎖/行鎖) 和 gap locks(間隙鎖,每次鎖住的不光是需要使用的數(shù)據(jù),還會鎖住這些數(shù)據(jù)附近的數(shù)據(jù))的結合
Next-Key Lock即在事務中select時使用如下方法加鎖,這樣在另一個事務對范圍內(nèi)的數(shù)據(jù)進行修改時就會阻塞(為什么有共享鎖會阻塞?不能在有共享鎖的記錄上加X鎖)
select * from table where id<6 lock in share mode; --共享鎖 select * from table where id<6 for update; --排他鎖關于next-key locks請參考https://www.cnblogs.com/zhoujinyi/p/3435982.html
5. MySQL常見的存儲引擎?
- MySQL 5.5之前使用的是MYISAM引擎,5.5以上版本用的是InnoDB引擎
- 二者區(qū)別:
| 事務 | 支持 | 不支持 |
| 鎖粒度 | 行鎖,適合高并發(fā) | 表鎖,不適合高并發(fā) |
| 是否默認 | 默認 | 非默認 |
| 支持外鍵 | 支持外鍵 | 不支持 |
| 適用場景 | 讀寫均衡,寫多讀少場景,需要事務 | 讀多寫少場景,不需要事務 |
| 全文索引 | 不支持(可以借助插件或者使用ElasticSearch) | 支持 |
6. MySQL的行鎖與表鎖,樂觀鎖悲觀鎖問題?
- 鎖粒度越小,并發(fā)支持度越高!
參考我的博客MySQL鎖相關問題
7. MySQL索引相關問題?
參考我的博客MySQL索引分析以及相關面試題
8. 數(shù)據(jù)庫設計三大范式?
- 第一范式(確保每列保持原子性)
- 第二范式(確保表中的每列都和主鍵相關)
- 第三范式(確保每列都和主鍵列直接相關,而不是間接相關):
- 比如在設計一個訂單數(shù)據(jù)表的時候,可以將客戶編號作為一個外鍵和訂單表建立相應的關系。而不可以在訂單表中添加關于客戶其它信息(比如姓名、所屬公司等)的字段。
文章參考:https://blog.csdn.net/huangyaa729/article/details/89924358
9. MySQL查詢的指令順序為?
- 查詢指令的順序為:SELECT=> FROM=> WHERE=> GROUP BY => HAVING => ORDER BY
10. MySQL中字段類型CHAR 和 VARCHA 的區(qū)別?
| 長度特點 | 長度固定,存儲字符 | 長度可變,存儲字符 |
| 長度不足情況 | 插入的長度小于定義長度時,則用空格填充 | 小于定義長度時,按實際插入長度存儲 |
| 性能 | 存取速度比varchar快得多 | 存取速度比char慢得多 |
| 使用場景 | 適合存儲很短的,固定長度的字符串,如手機號,MD5值等 | 適合用在長度不固定場景,如收貨地址,郵箱地址等 |
11. MySQL中字段類型DATETIME 和 TIMESTA的區(qū)別?
| datetime | 8 字節(jié) | 1000-01-01 00:00:00到 9999-12-31 23:59:59 | 存儲與時區(qū)無關,不會發(fā)生改變 |
| timestamp | 4 字節(jié) | 1970-01-01 00:00:01 到 2038-01-19 11:14:07 | 存儲的是與時區(qū)有關,隨數(shù)據(jù)庫的時區(qū)而發(fā)生改變 |
- 為什么timestamp只能到2038年
12. Mybatis中 # 和 $的區(qū)別?
- # 可以防止SQL 注入,它會將所有傳入的參數(shù)作為一個字符串來處理。# 防止SQL注入底層相當于是在操作JDBC時,使用PreparedStatement預編譯SQL語句來防止SQL注入
- $ 則將傳入的參數(shù)拼接到SQL上去執(zhí)行,一般用于表名和字段名參數(shù),$ 所對應的參數(shù)應該由服務器端提供。
- JDBC中的SQL注入案例:https://blog.csdn.net/ashleyjun/article/details/100558518
- SQL 注入案例:
有圖看到,我雖然沒有輸入對正確的用戶名,但是一次性查出了很多用戶信息,這就是SQL注入!
13. MySQL大數(shù)據(jù)量sql分頁優(yōu)化思路?
問題:線上數(shù)據(jù)庫的一個商品表數(shù)據(jù)量過千萬,做深度分頁的時候性能很慢,有什么優(yōu)化思路?
- 現(xiàn)象:千萬級別數(shù)據(jù)很正常,比如數(shù)據(jù)流水、日志記錄等,數(shù)據(jù)庫正常的深度分頁會很慢 - 慢的原因:select * from product limit N,M - MySQL執(zhí)行此類SQL時需要先掃描到N行,然后再去取M行,N越大,MySQL掃描的記錄數(shù)越多,SQL的性能就會越差解決思路:
-- 1、可以使用后端緩存Redis、前端緩存localstorage -- 2、使用ElasticSearch分頁搜索 -- 3、合理使用 mysql 索引 -- 比如title,cateory被設置為該表的復合索引,可以提高查詢效率 select title,cateory from product limit 1000000,100-- 4、如果id是自增且不存在中間刪除數(shù)據(jù),使用子查詢優(yōu)化,定位偏移位置的 id -- 這種方式比較耗時,因為需要先檢索前1000000行數(shù)據(jù),再檢索1000000-1000500的目標數(shù)據(jù) select * from oper_log where type='BUY' limit 1000000,100; -- 5秒 -- 因為id是主鍵索引,查詢速度快,先檢索前1000000行記錄的id值,并找到第1000000行記錄的id值 select id from oper_log where type='BUY' limit 1000000,1; -- 0.4秒 -- 再做一個子查詢,因為是主鍵遞增,所以id>=第1000000行記錄的id值,這樣就相當于跳過掃描前100000行數(shù)據(jù),直接從第1000000開始往后檢索100條數(shù)據(jù) select * from oper_log where type='BUY' and id>=(select id from oper_log where type='BUY' limit 1000000,1) limit 100; -- 0.8秒14. MySQL常見日志種類和作用?
- 1. redo 重做日志: - 作用:確保事務的持久性,防止在發(fā)生故障,臟頁未寫入磁盤。重啟數(shù)據(jù)庫會進行redo log執(zhí)行重做,到達事務一致性- 2. undo 回滾日志 - 作用:保證數(shù)據(jù)的原子性,記錄事務發(fā)生之前的數(shù)據(jù)的一個版本,用于回滾。innodb事務的可重復讀和讀取已提交 隔離級別就是通過mvcc+undo實現(xiàn)- 3. errorlog 錯誤日志 - 作用:Mysql本身啟動、停止、運行期間發(fā)生的錯誤信息- 4. slow query log 慢查詢?nèi)罩?- 作用:記錄執(zhí)行時間過長的sql,時間閾值可以配置,只記錄執(zhí)行成功- 5. binlog 二進制日志 - 作用:用于主從復制,實現(xiàn)主從同步- 6. relay log 中繼日志 - 作用:用于數(shù)據(jù)庫主從同步,將主庫發(fā)送來的binlog先保存在本地,然后從庫進行回放- 7. general log 普通日志 - 作用:記錄數(shù)據(jù)庫操作明細,默認關閉,開啟會降低數(shù)據(jù)庫性能15. MySQL事務的特性是通過什么實現(xiàn)的?
- 隔離性借助鎖來實現(xiàn)
- 持久性通過redo log重做日志實現(xiàn)
- 原子性通過undo log回滾日志實現(xiàn):MySQL數(shù)據(jù)庫在InnoDB存儲引擎中,還使用Undo Log來實現(xiàn)多版本并發(fā)控制
- 當delete一條記錄時,undo log中會記錄一條對應的 insert記錄;
- 當insert一條記錄時,undo log中會記錄一條對應的delete記錄;
- 當update一條記錄時,undo log中會記錄一條對應的update記錄;
- MySQL通過原子性、隔離性、持久性來保證一致性。C(一致性)是目的,A(原子性)、I(隔離性)、D(持久性)是手段,是為了保證一致性,數(shù)據(jù)庫提供的手段。數(shù)據(jù)庫必須要實現(xiàn)AID三大特性,才有可能實現(xiàn)一致性。
MySQL鎖相關請參考:MySQL鎖相關問題學習
總結
以上是生活随笔為你收集整理的小滴课堂MySQL相关面试题总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何找资源
- 下一篇: MIKE水动力笔记1_岸线及水深数据之依