面試系列之——數據庫知識(1)

事務

事務指的是滿足如下四個特性【ACID特性】的一組操作,可以通過 Commit 提交一個事務,也可以使用 Rollback 進行回滾。

  • 原子性(Atomicity)
    事務被視爲不可分割的最小單元,事務的所有操作要麼全部提交成功,要麼全部失敗回滾。
    回滾可以用回滾日誌來實現,回滾日誌記錄着事務所執行的修改操作,在回滾時反向執行這些修改操作即可。
  • 一致性(Consistency)
    數據庫在事務執行前後都保持一致性狀態。在一致性狀態下,所有事務對一個數據的讀取結果都是相同的。
  • 隔離性(Isolation)
    一個事務所做的修改在最終提交以前,對其它事務是不可見的。
  • 持久性(Durability)
    一旦事務提交,則其所做的修改將會永遠保存到數據庫中。即使系統發生崩潰,事務執行的結果也不能丟失。
    使用重做日誌來保證持久性。
    在這裏插入圖片描述
    事務的 ACID 特性概念簡單,但不是很好理解,主要是因爲這幾個特性不是一種平級關係:
  • 只有滿足一致性,事務的執行結果纔是正確的。
  • 在無併發的情況下,事務串行執行,隔離性一定能夠滿足。此時* 只要能滿足原子性,就一定能滿足一致性。
  • 在併發的情況下,多個事務並行執行,事務不僅要滿足原子性, 還需要滿足隔離性,才能滿足一致性。
  • 事務滿足持久化是爲了能應對數據庫崩潰的情況。
    在這裏插入圖片描述

併發一致性問題

在併發環境下,事務的隔離性很難保證,因此會出現很多併發一致性問題。
在這裏插入圖片描述
這裏在總結歸納一下:

  • 髒讀和不可重複讀的區別:髒讀是某一事務讀取了另一個事務未提交的髒數據,而不可重複讀則是讀取了前一事務提交的數據。
  • 不可重複讀和幻讀的異同:都是讀取了另一條已經提交的事務(這點就髒讀不同),所不同的是不可重複讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體(比如數據的個數)。

封鎖

封鎖粒度

MySQL 中提供了兩種封鎖粒度:行級鎖以及表級鎖。

我們在使用時應該儘量只鎖定需要修改的那部分數據,而不是所有的資源。鎖定的數據量越少,發生鎖爭用的可能就越小,系統的併發程度就越高。

但是加鎖需要消耗資源,鎖的各種操作(包括獲取鎖、釋放鎖、以及檢查鎖狀態)都會增加系統開銷。因此封鎖粒度越小,系統開銷就越大。

行鎖的優點:
1.當在許多線程中訪問不同的行時只存在少量鎖定衝突。
2.回滾時只有少量的更改
3.可以長時間鎖定單一的行。

行鎖的缺點:
1.比頁級或表級鎖定佔用更多的內存。
2.當在表的大部分中使用時,比頁級或表級鎖定速度慢,因爲你必須獲取更多的鎖。
3.如果你在大部分數據上經常進行GROUP BY操作或者必須經常掃描整個表,比其它鎖定明顯慢很多。
4.用高級別鎖定,通過支持不同的類型鎖定,你也可以很容易地調節應用程序,因爲其鎖成本小於行級鎖定。

在選擇封鎖粒度時,需要在鎖開銷和併發程度之間做一個權衡。
在這裏插入圖片描述

鎖的算法

三種鎖的算法:Record Lock、Gap Lock 和 Next-Key Lock

1.Record Lock
記錄鎖(Record Lock)是加到索引記錄上的鎖,假設我們存在下面的一張表 users:

  CREATE TABLE users(
        id INT NOT NULL AUTO_INCREMENT,
        last_name VARCHAR(255) NOT NULL,
        first_name VARCHAR(255),
        age INT,
        PRIMARY KEY(id),
        KEY(last_name),
        KEY(age)
    );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

如果我們使用 id 或者 last_name 作爲 SQL 中 WHERE 語句的過濾條件,那麼 InnoDB 就可以通過索引建立的 B+ 樹找到行記錄並添加索引,但是如果使用 first_name 作爲過濾條件時,由於 InnoDB 不知道待修改的記錄具體存放的位置,也無法對將要修改哪條記錄提前做出判斷就會鎖定整個表。

2.Gap Lock
記錄鎖是在存儲引擎中最爲常見的鎖,除了記錄鎖之外,InnoDB 中還存在間隙鎖(Gap Lock),間隙鎖是對索引記錄中的一段連續區域的鎖;當使用類似 SELECT * FROM users WHERE id BETWEEN 10 AND 20 FOR UPDATE; 的 SQL 語句時,就會阻止其他事務向表中插入 id = 15 的記錄,因爲整個範圍都被間隙鎖鎖定了。

間隙鎖是存儲引擎對於性能和併發做出的權衡,並且只用於某些事務隔離級別。

雖然間隙鎖中也分爲共享鎖和互斥鎖,不過它們之間並不是互斥的,也就是不同的事務可以同時持有一段相同範圍的共享鎖和互斥鎖,它唯一阻止的就是其他事務向這個範圍中添加新的記錄。

Gap Lock的作用是爲了阻止多個事務將記錄插入到同一個範圍內,這樣會導致幻讀的產生。用戶可以通過以下兩種服務顯式地關閉Gap Lock。
1.將事務的隔離級別設置爲READ COMMITTED
2.將參數innodb_locks_unsafe_for_binlog設置爲1

除了外鍵約束和唯一性檢查需要的Gap Lock,其餘情況僅使用Record Lock進行鎖定。這樣做破壞了事務的隔離性,並且對於replication會導致主動數據的不一致。

3.Next-Key Lock
Next-Key Lock是結合了Gap Lock和Record Lock的一種鎖定算法,其設置的目的是爲了解決幻讀問題。

當查詢的索引含有唯一屬性的時候,InnoDB存儲引擎會對Next-Key Lock進行優化,將其降爲Record Lock,即僅僅鎖住索引本身,而不是範圍,從而提高併發效率。

對於唯一值的鎖定,Next-Key Lock降級爲Record Lock僅存在於查詢所有的唯一索引列。若唯一索引由多個列組成,而查詢僅是查找多個唯一索引列中的其中一個,那麼查詢其實是range類型,而不是point類型的查詢。此時InnoDB存儲引擎依然使用Next-Key Lock進行鎖定。

鎖算法選擇

下面我們針對大部分的SQL類型分析是如何加鎖的,假設事務隔離級別爲可重複讀

select … from

不加任何類型的鎖

select…from lock in share mode

在掃描到的任何索引記錄上加共享的(shared)next-key lock,還有主鍵聚集索引加排它鎖

select…from for update

在掃描到的任何索引記錄上加排它的next-key lock,還有主鍵聚集索引加排它鎖

update…where delete from…where

在掃描到的任何索引記錄上加next-key lock,還有主鍵聚集索引加排它鎖

insert into…

簡單的insert會在insert的行對應的索引記錄上加一個排它鎖,這是一個record lock,並沒有gap,所以並不會阻塞其他session在gap間隙裏插入記錄。不過在insert操作之前,還會加一種鎖,官方文檔稱它爲insertion intention gap lock,也就是意向的gap鎖。這個意向gap鎖的作用就是預示着當多事務併發插入相同的gap空隙時,只要插入的記錄不是gap間隙中的相同位置,則無需等待其他session就可完成,這樣就使得insert操作無須加真正的gap lock。想象一下,如果一個表有一個索引idx_test,表中有記錄1和8,那麼每個事務都可以在2和7之間插入任何記錄,只會對當前插入的記錄加record lock,並不會阻塞其他session插入與自己不同的記錄,因爲他們並沒有任何衝突。

封鎖類型

1.讀寫鎖

  • 排它鎖(Exclusive),簡寫爲 X 鎖,又稱寫鎖。
  • 共享鎖(Shared),簡寫爲 S 鎖,又稱讀鎖。

他們滿足下面的兼容關係:

- X S
X x x
S x v

對應的是以下兩個規定:
1.一個事務對數據對象 A 加了 X 鎖,就可以對 A 進行讀取和更新。加鎖期間其它事務不能對 A 加任何鎖。
2.一個事務對數據對象 A 加了 S 鎖,可以對 A 進行讀取操作,但是不能進行更新操作。加鎖期間其它事務能對 A 加 S 鎖,但是不能加 X 鎖。

2.意向鎖
使用意向鎖(Intention Locks)可以更容易地支持多粒度封鎖

在存在行級鎖和表級鎖的情況下,事務 T 想要對錶 A 加 X 鎖,就需要先檢測是否有其它事務對錶 A 或者表 A 中的任意一行加了鎖,那麼就需要對錶 A 的每一行都檢測一次,這是非常耗時的。

意向鎖在原來的 X/S 鎖之上引入了 IX/IS,IX/IS 都是表鎖,用來表示一個事務想要在表中的某個數據行上加 X 鎖或 S 鎖。有以下兩個規定:

  • 一個事務在獲得某個數據行對象的 S 鎖之前,必須先獲得表的 IS 鎖或者更強的鎖;
  • 一個事務在獲得某個數據行對象的 X 鎖之前,必須先獲得表的 IX 鎖。

通過引入意向鎖,事務 T 想要對錶 A 加 X 鎖,只需要先檢測是否有其它事務對錶 A 加了 X/IX/S/IS 鎖,如果加了就表示有其它事務正在使用這個表或者表中某一行的鎖,因此事務 T 加 X 鎖失敗。

各種鎖的兼容關係如下:
在這裏插入圖片描述
解釋如下:

  • 任意 IS/IX 鎖之間都是兼容的,因爲它們只是表示想要對錶加鎖,而不是真正加鎖;
  • S 鎖只與 S 鎖和 IS 鎖兼容,也就是說事務 T 想要對數據行加 S 鎖,其它事務可以已經獲得對錶或者表中的行的 S 鎖。

封鎖協議在這裏插入圖片描述

這裏順便提一下在 MySQL隱式與顯示鎖定:
在MySQL的 InnoDB 存儲引擎採用的是兩段鎖協議,會根據隔離級別在需要的時候自動加鎖,並且所有的鎖都是在同一時刻被釋放,這被稱爲隱式鎖定。

InnoDB 也可以使用特定的語句進行顯示鎖定:

SELECT ... LOCK In SHARE MODE;
SELECT ... FOR UPDATE;
  • 1
  • 2

隔離級別

1.未提交讀(Read Uncommitted)
名稱解釋:事務中的修改,即使沒有提交,對其它事務也是可見的。
含義:限制同一數據寫事務時禁止其他寫事務。解決”更新丟失”。(一事務寫時禁止其他事務寫)
所需要的鎖:排他寫鎖
2.提交讀(Read Committed)
名稱解釋:一個事務只能讀取已經提交的事務所做的修改。換句話說,一個事務所做的修改在提交之前對其它事務是不可見的。
含義:限制同一數據寫事務時禁止其它讀寫事務。解決”髒讀”,以及”更新丟失”。(一事務寫時禁止其他事務讀寫)
所需要的鎖:排他寫鎖,瞬間共享讀鎖
3.可重複讀(Repeatable Read)
名稱解釋:保證在同一個事務中多次讀取同樣數據的結果是一樣的。
含義:限制同一數據寫事務時禁止其他讀寫事務,讀事務時禁止其他寫事務(允許讀)。解決”不可重複讀”,以及”更新丟失”和”髒讀”。(一事務寫時禁止其他事務讀寫、一事務讀時禁止其他事務寫),注意他沒有解決幻讀,解決幻讀需要增加範圍鎖(range lock)或者表鎖。
所需要的鎖:排他寫鎖,共享讀鎖。
4.可串行化(Serializable)
名稱解釋:強制事務串行執行。
含義解釋:限制所有讀寫事務都必須串行化實行。它要求事務序列化執行,事務只能一個接着一個地執行,但不能併發執行。如果僅僅通過“行級鎖”是無法實現事務序列化的,必須通過其他機制保證新插入的數據不會被剛執行查詢操作的事務訪問到。(一事務寫時禁止其他事務讀寫、一事務讀時禁止其他事務讀寫)
所須的鎖:範圍鎖或表鎖

下表是各隔離級別對各種異常的控制能力:
在這裏插入圖片描述

常見的數據庫事務隔離

(2019.12.31更新)

數據庫 默認隔離級別
MySQL 可重複讀(Repeatable Read)
Oracle 提交讀(Read Committed)
SQLServer 提交讀(Read Committed)
PostgreSQL 提交讀(Read Committed)

在MySQL數據庫中,支持上面四種隔離級別,默認的爲Repeatable read (可重複讀);此外,MySQL的Repeatable Read隔離級別也解決了幻讀問題(通過Next-key lock加鎖方法即範圍鎖解決不可重複讀和幻讀問題,如select * from t where a>10會對key爲[10,infinite)範圍的行加鎖,這樣其他事務就不能對此範圍內key對應的行更改)達到了SQL、SQL2標準中的Serializable級別。

在Oracle數據庫中,只支持Serializable (串行化)級別和Read committed (讀已提交)這兩種級別,其中默認的爲Read committed級別。

在MySQL數據庫中查看當前事務的隔離級別:

select @@tx_isolation;
  • 1

在MySQL數據庫中設置事務的隔離 級別:

set  [glogal | session]  transaction isolation level 隔離級別名稱; //設置全部連接或當前連接的事務隔離級別

set tx_isolation=’隔離級別名稱; //設置當前連接的事務隔離級別

  • 1
  • 2
  • 3

關係數據庫設計理論

函數依賴

記 A->B 表示 A 函數決定 B,也可以說 B 函數依賴於 A。

如果 {A1,A2,… ,An} 是關係的一個或多個屬性的集合,該集合函數決定了關係的其它所有屬性並且是最小的,那麼該集合就稱爲鍵碼(主鍵)

對於 A->B,如果能找到 A 的真子集 A’,使得 A’-> B,那麼 A->B 就是部分函數依賴,否則就是完全函數依賴。

對於 A->B,B->C,則 A->C 是一個傳遞函數依賴。

範式

在這裏插入圖片描述
1. 第一範式 (1NF)
屬性不可分。

2. 第二範式 (2NF)
每個非主屬性完全函數依賴於鍵碼。
可以通過分解來滿足。

3. 第三範式 (3NF)
每一個非主屬性即不會部分依賴於鍵碼也不傳遞函數依賴於鍵碼。

4.BCNF
所有非主屬性對每一個碼都是完全函數依賴;
所得的主屬性對每一個不包含他的碼,也是完全函數依賴;
沒有任何屬性完全函數依賴於非碼的任何一個屬性;

ER圖

Entity-Relationship,有三個組成部分:實體、屬性、聯繫。

用來進行關係型數據庫系統的概念設計
在這裏插入圖片描述
關係型數據庫和非關係數據庫之間的區別
上述南國講的大部分是依據關係型數據庫來講解的知識點,有關於關係型數據庫和非關係型數據庫的比較,南國這裏推薦我認識的以爲學長寫的博客:如何看待當今多種多樣的數據庫

參看資料:
CS-Notes數據庫系統原理

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