常見問題總結什么是MySQL?
MySQL 是一種關系型數據庫,在Java企業級開發中非常常用,因為 MySQL 是開源免費的,并且方便擴展。阿里巴巴數據庫系統也大量用到了 MySQL,因此它的穩定性是有保障的。MySQL是開放源代碼的,因此任何人都可以在 GPL( ) 的許可下下載并根據個性化的需要對其進行修改。MySQL的默認端口號是3306。
存儲引擎一些常用命令
查看MySQL提供的所有存儲引擎
mysql> show engines;
從上圖我們可以查看出 MySQL 當前默認的存儲引擎是,并且在5.7版本所有的存儲引擎中只有 是事務性存儲引擎,也就是說只有 支持事務。
查看MySQL當前默認的存儲引擎
我們也可以通過下面的命令查看默認的存儲引擎。
mysql> show variables like '%storage_engine%';
查看表的存儲引擎
show table status like "table_name" ;
和區別
是MySQL的默認數據庫引擎(5.5版之前)。雖然性能極佳,而且提供了大量的特性,包括全文索引、壓縮、空間函數等,但不支持事務和行級鎖,而且最大的缺陷就是崩潰后無法安全恢復。不過,5.5版本之后,MySQL引入了(事務性數據庫引擎),MySQL 5.5版本后默認的存儲引擎為。
大多數時候我們使用的都是 存儲引擎,但是在某些情況下使用 也是合適的比如讀密集的情況下。(如果你不介意 崩潰恢復問題的話)。
兩者的對比:
是否支持行級鎖 : 只有表級鎖(table-level ),而 支持行級鎖(row-level )和表級鎖,默認為行級鎖。是否支持事務和崩潰后的安全恢復: 強調的是性能高級數據庫系統與實現,每次查詢具有原子性,其執行速度比類型更快,但是不提供事務支持。但是 提供事務支持事務,外部鍵等高級數據庫功能。 具有事務()、回滾()和崩潰修復能力(crash )的事務安全(-safe (ACID ))型表。是否支持外鍵: 不支持,而支持。是否支持MVCC :僅 支持。應對高并發事務, MVCC比單純的加鎖更高效;MVCC只在 READ 和 READ 兩個隔離級別下工作;MVCC可以使用 樂觀()鎖 和 悲觀()鎖來實現;各數據庫中MVCC實現并不統一。......
《MySQL高性能》上面有一句話這樣寫到:
不要輕易相信“比快”之類的經驗之談,這個結論往往不是絕對的。在很多我們已知場景中,的速度都可以讓望塵莫及,尤其是用到了聚簇索引,或者需要訪問的數據都可以放入內存的應用。
一般情況下我們選擇 都是沒有問題的,但是某些情況下你并不在乎可擴展能力和并發能力,也不需要事務支持,也不在乎崩潰后的安全恢復問題的話,選擇也是一個不錯的選擇。但是一般情況下,我們都是需要考慮到這些問題的。
字符集及校對規則
字符集指的是一種從二進制編碼到某類字符符號的映射。校對規則則是指某種字符集下的排序規則。MySQL中每一種字符集都會對應一系列的校對規則。
MySQL采用的是類似繼承的方式指定字符集的默認值,每個數據庫以及每張數據表都有自己的默認值,他們逐層繼承。比如:某個庫中所有表的默認字符集將是該數據庫所指定的字符集(這些表在沒有指定字符集的情況下,才會采用默認字符集)
索引
MySQL索引使用的數據結構主要有BTree索引 和 哈希索引 。對于哈希索引來說,底層的數據結構就是哈希表,因此在絕大多數需求為單條記錄查詢的時候,可以選擇哈希索引,查詢性能最快;其余大部分場景,建議選擇BTree索引。
MySQL的BTree索引使用的是B樹中的B+Tree,但對于主要的兩種存儲引擎的實現方式是不同的。
更多關于索引的內容可以查看文檔首頁MySQL目錄下關于索引的詳細總結。
查詢緩存的使用
執行查詢語句的時候,會先查詢緩存。不過,MySQL 8.0 版本后移除,因為這個功能不太實用
f加入以下配置,重啟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比較合適。此外,還可以通過和來控制某個查詢語句是否需要緩存:
select sql_no_cache count(*) from usr;
什么是事務?
事務是邏輯上的一組操作,要么都執行,要么都不執行。
事務最經典也經常被拿出來說例子就是轉賬了。假如小明要給小紅轉賬1000元,這個轉賬會涉及到兩個關鍵操作就是:將小明的余額減少1000元,將小紅的余額增加1000元。萬一在這兩個操作之間突然出現錯誤比如銀行系統崩潰,導致小明余額減少而小紅的余額沒有增加高級數據庫系統與實現,這樣就不對了。事務就是保證這兩個關鍵操作要么都成功,要么都要失敗。
事物的四大特性(ACID)
原子性(): 事務是最小的執行單位,不允許分割。事務的原子性確保動作要么全部完成,要么完全不起作用;一致性(): 執行事務前后,數據保持一致,多個事務對同一個數據讀取的結果是相同的;隔離性(): 并發訪問數據庫時,一個用戶的事務不被其他事務所干擾,各并發事務之間數據庫是獨立的;持久性(): 一個事務被提交之后。它對數據庫中數據的改變是持久的,即使數據庫發生故障也不應該對其有任何影響。并發事務帶來哪些問題?
在典型的應用程序中,多個事務并發運行,經常會操作相同的數據來完成各自的任務(多個用戶對同一數據進行操作)。并發雖然是必須的,但可能會導致以下的問題。
不可重復讀和幻讀區別:
不可重復讀的重點是修改比如多次讀取一條記錄發現其中某些列的值被修改,幻讀的重點在于新增或者刪除比如多次讀取一條記錄發現記錄增多或減少了。
事務隔離級別有哪些?MySQL的默認隔離級別是?
SQL 標準定義了四個隔離級別:
隔離級別
臟讀
不可重復讀
幻影讀
READ-
√
√
√
READ-
×
√
√
-READ
×
×
√
×
×
×
MySQL 存儲引擎的默認支持的隔離級別是 -READ(可重讀)。我們可以通過 @@;命令來查看
mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
這里需要注意的是:與 SQL 標準不同的地方在于 存儲引擎在 -READ(可重讀)
事務隔離級別下使用的是Next-Key Lock 鎖算法,因此可以避免幻讀的產生,這與其他數據庫系統(如 SQL )
是不同的。所以說 存儲引擎的默認支持的隔離級別是 -READ(可重讀) 已經可以完全保證事務的隔離性要求,即達到了
SQL標準的 (可串行化) 隔離級別。因為隔離級別越低,事務請求的鎖越少,所以大部分數據庫系統的隔離級別都是 READ-(讀取提交內容) ,但是你要知道的是 存儲引擎默認使用 -READ(可重讀) 并不會有任何性能損失。
存儲引擎在 分布式事務 的情況下一般會用到 (可串行化) 隔離級別。
鎖機制與鎖算法
和存儲引擎使用的鎖:
表級鎖和行級鎖對比:
存儲引擎的鎖的算法有三種:
相關知識點:
對于行的查詢使用next-key - 為了解決 幻讀問題當查詢的索引含有唯一屬性時,將next-key lock降級為 鎖設計的目的是為了阻止多個事務將記錄插入到同一范圍內,而這會導致幻讀問題的產生有兩種方式顯式關閉gap鎖:(除了外鍵約束和唯一性檢查外,其余情況僅使用 lock) A. 將事務隔離級別設置為RC B. 將參數設置為1大表優化
當MySQL單表記錄數過大時,數據庫的CRUD性能會明顯下降,一些常見的優化措施如下:
1. 限定數據的范圍
務必禁止不帶任何限制數據范圍條件的查詢語句。比如:我們當用戶在查詢訂單歷史的時候,我們可以控制在一個月的范圍內;
2. 讀/寫分離
經典的數據庫拆分方案,主庫負責寫,從庫負責讀;
3. 垂直分區
根據數據庫里面數據表的相關性進行拆分。 例如,用戶表中既有用戶的登錄信息又有用戶的基本信息,可以將用戶表拆分成兩個單獨的表,甚至放到單獨的庫做分庫。
簡單來說垂直拆分是指數據表列的拆分,把一張列比較多的表拆分為多張表。 如下圖所示,這樣來說大家應該就更容易理解了。
4. 水平分區
保持數據表結構不變,通過某種策略存儲數據分片。這樣每一片數據分散到不同的表或者庫中,達到了分布式的目的。 水平拆分可以支撐非常大的數據量。
水平拆分是指數據表行的拆分,表的行數超過200萬行時,就會變慢,這時可以把一張的表的數據拆成多張表來存放。舉個例子:我們可以將用戶信息表拆分成多個用戶信息表,這樣就可以避免單一表數據量過大對性能造成影響。
水平拆分可以支持非常大的數據量。需要注意的一點是:分表僅僅是解決了單一表數據過大的問題,但由于表的數據還是在同一臺機器上,其實對于提升MySQL并發能力沒有什么意義,所以 水平拆分最好分庫 。
水平拆分能夠 支持非常大的數據量存儲,應用端改造也少,但 分片事務難以解決 ,跨節點Join性能較差,邏輯復雜。《Java工程師修煉之道》的作者推薦 盡量不要對數據進行分片,因為拆分會帶來邏輯、部署、運維的各種復雜度 ,一般的數據表在優化得當的情況下支撐千萬以下的數據量是沒有太大問題的。如果實在要分片,盡量選擇客戶端分片架構,這樣可以減少一次和中間件的網絡I/O。
下面補充一下數據庫分片的兩種常見方案:
解釋一下什么是池化設計思想。什么是數據庫連接池?為什么需要數據庫連接池?
池話設計應該不是一個新名詞。我們常見的如java線程池、jdbc連接池、redis連接池等就是這類設計的代表實現。這種設計會初始預設資源,解決的問題就是抵消每次獲取資源的消耗,如創建線程的開銷,獲取遠程連接的開銷等。就好比你去食堂打飯,打飯的大媽會先把飯盛好幾份放那里,你來了就直接拿著飯盒加菜即可,不用再臨時又盛飯又打菜,效率就高了。除了初始化資源,池化設計還包括如下這些特征:池子的初始值、池子的活躍值、池子的最大值等,這些特征可以直接映射到java線程池和數據庫連接池的成員屬性中。——這篇文章對池化設計思想介紹的還不錯,直接復制過來,避免重復造輪子了。
數據庫連接本質就是一個 的連接。數據庫服務端還要維護一些緩存和用戶權限信息之類的 所以占用了一些內存。我們可以把數據庫連接池是看做是維護的數據庫連接的緩存,以便將來需要對數據庫的請求時可以重用這些連接。為每個用戶打開和維護數據庫連接,尤其是對動態數據庫驅動的網站應用程序的請求,既昂貴又浪費資源。在連接池中,創建連接后,將其放置在池中,并再次使用它,因此不必建立新的連接。如果使用了所有連接,則會建立一個新連接并將其添加到池中。連接池還減少了用戶必須等待建立與數據庫的連接的時間。
分庫分表之后,id 主鍵如何處理?
因為要是分成多個表之后,每個表都是從 1 開始累加,這樣是不對的,我們需要一個全局唯一的 id 來支持。
生成全局 id 有下面這幾種方式:
最后給大家分享系列的學習筆記和面試題,包含面試題、 cloud面試題、 boot面試題、教程筆記、 boot教程筆記、最新阿里巴巴開發手冊(63頁PDF總結)、2022年Java面試手冊。一共整理了1184頁PDF文檔。私信博主(777),祝大家更上一層樓!!!