相關閱讀: 2.7w字!Java基礎面試題/知識點總結!(2021 最新版)mysql
這篇文章以前發過,不過,我最近對其進行了重構完善而且修復了不少小問題。因此,在再同步一下!git
內容很硬!強烈建議小夥伴們花 10 分鐘左右閱讀一遍!程序員
顧名思義,關係型數據庫就是一種創建在關係模型的基礎上的數據庫。關係模型代表了數據庫中所存儲的數據之間的聯繫(一對1、一對多、多對多)。github
關係型數據庫中,咱們的數據都被存放在了各類表中(好比用戶表),表中的每一行就存放着一條數據(好比一個用戶的信息)。面試
大部分關係型數據庫都使用 SQL 來操做數據庫中的數據。而且,大部分關係型數據庫都支持事務的四大特性(ACID)。算法
有哪些常見的關係型數據庫呢?sql
MySQL、PostgreSQL、Oracle、SQL Server、SQLite(微信本地的聊天記錄的存儲就是用的 SQLite) ......。數據庫
MySQL 是一種關係型數據庫,主要用於持久化存儲咱們的系統中的一些數據好比用戶信息。緩存
因爲 MySQL 是開源免費而且比較成熟的數據庫,所以,MySQL 被大量使用在各類系統中。任何人均可以在 GPL(General Public License) 的許可下下載並根據個性化的須要對其進行修改。MySQL 的默認端口號是3306。安全
查看 MySQL 提供的全部存儲引擎
mysql> show engines;
複製代碼
從上圖咱們能夠查看出 MySQL 當前默認的存儲引擎是 InnoDB,而且在 5.7 版本全部的存儲引擎中只有 InnoDB 是事務性存儲引擎,也就是說只有 InnoDB 支持事務。
查看 MySQL 當前默認的存儲引擎
咱們也能夠經過下面的命令查看默認的存儲引擎。
mysql> show variables like '%storage_engine%';
複製代碼
查看錶的存儲引擎
show table status like "table_name" ;
複製代碼
MySQL 5.5 以前,MyISAM 引擎是 MySQL 的默認存儲引擎,可謂是風光一時。
雖然,MyISAM 的性能還行,各類特性也還不錯(好比全文索引、壓縮、空間函數等)。可是,MyISAM 不支持事務和行級鎖,並且最大的缺陷就是崩潰後沒法安全恢復。
5.5 版本以後,MySQL 引入了 InnoDB(事務性數據庫引擎),MySQL 5.5 版本後默認的存儲引擎爲 InnoDB。小夥子,必定要記好這個 InnoDB ,你每次使用 MySQL 數據庫都是用的這個存儲引擎吧?
言歸正傳!我們下面仍是來簡單對比一下二者:
1.是否支持行級鎖
MyISAM 只有表級鎖(table-level locking),而 InnoDB 支持行級鎖(row-level locking)和表級鎖,默認爲行級鎖。
也就說,MyISAM 一鎖就是鎖住了整張表,這在併發寫的狀況下是多麼滴憨憨啊!這也是爲何 InnoDB 在併發寫的時候,性能更牛皮了!
2.是否支持事務
MyISAM 不提供事務支持。
InnoDB 提供事務支持,具備提交(commit)和回滾(rollback)事務的能力。
3.是否支持外鍵
MyISAM 不支持,而 InnoDB 支持。
🌈 拓展一下:
通常咱們也是不建議在數據庫層面使用外鍵的,應用層面能夠解決。不過,這樣會對數據的一致性形成威脅。具體要不要使用外鍵仍是要根據你的項目來決定。
4.是否支持數據庫異常崩潰後的安全恢復
MyISAM 不支持,而 InnoDB 支持。
使用 InnoDB 的數據庫在異常崩潰後,數據庫從新啓動的時候會保證數據庫恢復到崩潰前的狀態。這個恢復的過程依賴於 redo log
。
🌈 拓展一下:
REPEATABLE-READ
)。5.是否支持 MVCC
MyISAM 不支持,而 InnoDB 支持。
講真,這個對比有點廢話,畢竟 MyISAM 連行級鎖都不支持。
MVCC 能夠看做是行級鎖的一個升級,能夠有效減小加鎖操做,提供性能。
大多數時候咱們使用的都是 InnoDB 存儲引擎,在某些讀密集的狀況下,使用 MyISAM 也是合適的。不過,前提是你的項目不介意 MyISAM 不支持事務、崩潰恢復等缺點(但是~咱們通常都會介意啊!)。
《MySQL 高性能》上面有一句話這樣寫到:
不要輕易相信「MyISAM 比 InnoDB 快」之類的經驗之談,這個結論每每不是絕對的。在不少咱們已知場景中,InnoDB 的速度均可以讓 MyISAM 可望不可即,尤爲是用到了聚簇索引,或者須要訪問的數據均可以放入內存的應用。
通常狀況下咱們選擇 InnoDB 都是沒有問題的,可是某些狀況下你並不在意可擴展能力和併發能力,也不須要事務支持,也不在意崩潰後的安全恢復問題的話,選擇 MyISAM 也是一個不錯的選擇。可是通常狀況下,咱們都是須要考慮到這些問題的。
所以,對於我們平常開發的業務系統來講,你幾乎找不到什麼理由再使用 MyISAM 做爲本身的 MySQL 數據庫的存儲引擎。
MyISAM 和 InnoDB 存儲引擎使用的鎖:
表級鎖和行級鎖對比:
InnoDB 存儲引擎的鎖的算法有三種:
執行查詢語句的時候,會先查詢緩存。不過,MySQL 8.0 版本後移除,由於這個功能不太實用
my.cnf
加入如下配置,重啓 MySQL 開啓查詢緩存
query_cache_type=1
query_cache_size=600000
複製代碼
MySQL 執行如下命令也能夠開啓查詢緩存
set global query_cache_type=1;
set global query_cache_size=600000;
複製代碼
如上,開啓查詢緩存後在一樣的查詢條件以及數據狀況下,會直接在緩存中返回結果。這裏的查詢條件包括查詢自己、當前要查詢的數據庫、客戶端協議版本號等一些可能影響結果的信息。所以任何兩個查詢在任何字符上的不一樣都會致使緩存不命中。此外,若是查詢中包含任何用戶自定義函數、存儲函數、用戶變量、臨時表、MySQL 庫中的系統表,其查詢結果也不會被緩存。
緩存創建以後,MySQL 的查詢緩存系統會跟蹤查詢中涉及的每張表,若是這些表(數據或結構)發生變化,那麼和這張表相關的全部緩存數據都將失效。
緩存雖然可以提高數據庫的查詢性能,可是緩存同時也帶來了額外的開銷,每次查詢後都要作一次緩存操做,失效後還要銷燬。 所以,開啓查詢緩存要謹慎,尤爲對於寫密集的應用來講更是如此。若是開啓,要注意合理控制緩存空間大小,通常來講其大小設置爲幾十 MB 比較合適。此外,還能夠經過 sql_cache 和 sql_no_cache 來控制某個查詢語句是否須要緩存:
select sql_no_cache count(*) from usr;
複製代碼
一言蔽之,事務是邏輯上的一組操做,要麼都執行,要麼都不執行。
能夠簡單舉一個例子不?
事務最經典也常常被拿出來講例子就是轉帳了。假如小明要給小紅轉帳 1000 元,這個轉帳會涉及到兩個關鍵操做就是:
事務會把這兩個操做就能夠當作邏輯上的一個總體,這個總體包含的操做要麼都成功,要麼都要失敗。
這樣就不會出現小明餘額減小而小紅的餘額卻並無增長的狀況。
數據庫事務在咱們平常開發中接觸的最多了。若是你的項目屬於單體架構的話,你接觸到的每每就是數據庫事務了。
平時,咱們在談論事務的時候,若是沒有特指分佈式事務,每每指的就是數據庫事務。
那數據庫事務有什麼做用呢?
簡單來講:數據庫事務能夠保證多個對數據庫的操做(也就是 SQL 語句)構成一個邏輯上的總體。構成這個邏輯上的總體的這些數據庫操做遵循:要麼所有執行成功,要麼所有不執行 。
# 開啓一個事務
START TRANSACTION;
# 多條 SQL 語句
SQL1,SQL2...
## 提交事務
COMMIT;
複製代碼
另外,關係型數據庫(例如:MySQL
、SQL Server
、Oracle
等)事務都有 ACID 特性:
Atomicity
) : 事務是最小的執行單位,不容許分割。事務的原子性確保動做要麼所有完成,要麼徹底不起做用;Consistency
): 執行事務先後,數據保持一致,例如轉帳業務中,不管事務是否成功,轉帳者和收款人的總額應該是不變的;Isolation
): 併發訪問數據庫時,一個用戶的事務不被其餘事務所幹擾,各併發事務之間數據庫是獨立的;Durabilily
): 一個事務被提交以後。它對數據庫中數據的改變是持久的,即便數據庫發生故障也不該該對其有任何影響。數據事務的實現原理呢?
咱們這裏以 MySQL 的 InnoDB 引擎爲例來簡單說一下。
MySQL InnoDB 引擎使用 redo log(重作日誌) 保證事務的持久性,使用 undo log(回滾日誌) 來保證事務的原子性。
MySQL InnoDB 引擎經過 鎖機制、MVCC 等手段來保證事務的隔離性( 默認支持的隔離級別是 REPEATABLE-READ
)。
保證了事務的持久性、原子性、隔離性以後,一致性才能獲得保障。
在典型的應用程序中,多個事務併發運行,常常會操做相同的數據來完成各自的任務(多個用戶對同一數據進行操做)。併發雖然是必須的,但可能會致使如下的問題。
不可重複讀和幻讀區別:
不可重複讀的重點是修改好比屢次讀取一條記錄發現其中某些列的值被修改,幻讀的重點在於新增或者刪除好比屢次讀取一條記錄發現記錄增多或減小了。
SQL 標準定義了四個隔離級別:
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
MySQL InnoDB 存儲引擎的默認支持的隔離級別是 REPEATABLE-READ(可重讀)。咱們能夠經過SELECT @@tx_isolation;
命令來查看,MySQL 8.0 該命令改成SELECT @@transaction_isolation;
mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
複製代碼
這裏須要注意的是:與 SQL 標準不一樣的地方在於 InnoDB 存儲引擎在 REPEATABLE-READ(可重讀) 事務隔離級別下使用的是 Next-Key Lock 鎖算法,所以能夠避免幻讀的產生,這與其餘數據庫系統(如 SQL Server)是不一樣的。因此說 InnoDB 存儲引擎的默認支持的隔離級別是 REPEATABLE-READ(可重讀) 已經能夠徹底保證事務的隔離性要求,即達到了 SQL 標準的 SERIALIZABLE(可串行化) 隔離級別。
🐛 問題更正:MySQL InnoDB 的 REPEATABLE-READ(可重讀)並不保證避免幻讀,須要應用使用加鎖讀來保證。而這個加鎖度使用到的機制就是 Next-Key Locks。
由於隔離級別越低,事務請求的鎖越少,因此大部分數據庫系統的隔離級別都是 READ-COMMITTED(讀取提交內容) ,可是你要知道的是 InnoDB 存儲引擎默認使用 REPEATABLE-READ(可重讀) 並不會有任何性能損失。
InnoDB 存儲引擎在 分佈式事務 的狀況下通常會用到 SERIALIZABLE(可串行化) 隔離級別。
🌈 拓展一下(如下內容摘自《MySQL 技術內幕:InnoDB 存儲引擎(第 2 版)》7.7 章):
InnoDB 存儲引擎提供了對 XA 事務的支持,並經過 XA 事務來支持分佈式事務的實現。分佈式事務指的是容許多個獨立的事務資源(transactional resources)參與到一個全局的事務中。事務資源一般是關係型數據庫系統,但也能夠是其餘類型的資源。全局事務要求在其中的全部參與的事務要麼都提交,要麼都回滾,這對於事務原有的 ACID 要求又有了提升。另外,在使用分佈式事務時,InnoDB 存儲引擎的事務隔離級別必須設置爲 SERIALIZABLE。
最後再推薦一個很是不錯的 Java 教程類開源項目:JavaGuide 。我在大三開始準備秋招面試的時候,建立了 JavaGuide 這個項目。目前這個項目已經有 100k+的 star,相關閱讀:《1049 天,100K!簡單覆盤!》 。
對於你學習 Java 以及準備 Java 方向的面試都頗有幫助!正如做者說的那樣,這是一份:涵蓋大部分 Java 程序員所須要掌握的核心知識的 Java 學習+面試指南!
相關推薦:
我是 Guide哥,擁抱開源,喜歡烹飪。開源項目 JavaGuide 做者,Github:Snailclimb - Overview 。將來幾年,但願持續完善 JavaGuide,爭取可以幫助更多學習 Java 的小夥伴!共勉!凎!點擊查看個人2020年工做彙報!
《高性能 MySQL》