數據庫與MySQL進階(4)

1,事務

  事務指的是知足 ACID 特性的一組操做,能夠經過 Commit 提交一個事務,也可使用 Rollback 進行回滾。html

 

 1.1 ACID四大特性

原子性(Atomicity)

  事務被視爲不可分割的最小單元,事務的全部操做要麼所有提交成功,要麼所有失敗回滾。git

  回滾能夠用回滾日誌來實現,回滾日誌記錄着事務所執行的修改操做,在回滾時反向執行這些修改操做便可。github

一致性(Consistency)

  數據庫在事務執行先後都保持一致性狀態。在一致性狀態下,全部事務對一個數據的讀取結果都是相同的。sql

隔離性(Isolation)

  一個事務所作的修改在最終提交之前,對其它事務是不可見的。數據庫

持久性(Durability)

  一旦事務提交,則其所作的修改將會永遠保存到數據庫中。即便系統發生崩潰,事務執行的結果也不能丟失,使用重作日誌來保證持久性。併發

事務的 ACID 特性概念簡單,但不是很好理解,主要是由於這幾個特性不是一種平級關係:數據庫設計

  • 只有知足一致性,事務的執行結果纔是正確的。
  • 在無併發的狀況下,事務串行執行,隔離性必定可以知足。此時只要能知足原子性,就必定能知足一致性。
  • 在併發的狀況下,多個事務並行執行,事務不只要知足原子性,還須要知足隔離性,才能知足一致性。
  • 事務知足持久化是爲了能應對數據庫崩潰的狀況。

1.2 AUTOCOMMIT【默認提交】

  MySQL 默認採用自動提交模式。也就是說,若是不顯式使用START TRANSACTION語句來開始一個事務,那麼每一個查詢都會被當作一個事務自動提交。函數

1.3 併發一致性問題

①併發修改;②修讀撤;③讀修讀1;④讀修讀2;性能

  在併發環境下,事務的隔離性很難保證,所以會出現不少併發一致性問題。spa

  1.3.1 丟失修改【併發修改一個數據致使其中一個丟失!!!】

  T1 和 T2 兩個事務都對一個數據進行修改,T1 先修改,T2 隨後修改,T2 的修改覆蓋了 T1 的修改。

  1.3.2 讀髒數據【修改後又撤銷、同時有讀取操做讀到了修改的數據!!!】

  T1 修改一個數據,T2 隨後讀取這個數據。若是 T1 撤銷了此次修改,那麼 T2 讀取的數據是髒數據。

  1.3.3 不可重複讀【連續讀取兩次數據結果不一樣】

  T2 讀取一個數據,T1 對該數據作了修改。若是 T2 再次讀取這個數據,此時讀取的結果和第一次讀取的結果不一樣。

  1.3.4幻影讀【讀取範圍值,連續讀取結果有變化】

  T1 讀取某個範圍的數據,T2 在這個範圍內插入新的數據,T1 再次讀取這個範圍的數據,此時讀取的結果和和第一次讀取的結果不一樣。

  產生併發不一致性問題主要緣由是破壞了事務的隔離性,解決方法是經過併發控制來保證隔離性。併發控制能夠經過封鎖來實現,可是封鎖操做須要用戶本身控制,至關複雜。數據庫管理系統提供了事務的隔離級別,讓用戶以一種更輕鬆的方式處理併發一致性問題。

1.4封鎖

  1.4.1封鎖粒度

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

  應該儘可能只鎖定須要修改的那部分數據,而不是全部的資源。鎖定的數據量越少,發生鎖爭用的可能就越小,系統的併發程度就越高。【性能角度——優先使用行鎖級】

  可是加鎖須要消耗資源,鎖的各類操做(包括獲取鎖、釋放鎖、以及檢查鎖狀態)都會增長系統開銷。所以封鎖粒度越小,系統開銷就越大。【耗能角度——優先使用表鎖級】

  在選擇封鎖粒度時,須要在鎖開銷和併發程度之間作一個權衡。【取一個平衡值】

  1.4.2讀寫鎖【排他鎖優於共享鎖,寫權限更高】

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

  有如下兩個規定:

  • 一個事務對數據對象 A 加了 X 鎖,就能夠對 A 進行讀取和更新。加鎖期間其它事務不能對 A 加任何鎖。
  • 一個事務對數據對象 A 加了 S 鎖,能夠對 A 進行讀取操做,可是不能進行更新操做。加鎖期間其它事務能對 A 加 S 鎖,可是不能加 X 鎖。

  1.4.3 意向鎖【將來要發生,當下還沒發生】

  使用意向鎖(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 鎖。

 

1.5 封鎖協議

1.5.1 三級封鎖協議

  ①一級封鎖協議【X鎖讀鎖】-丟失修改問題

  事務 T 要修改數據 A 時必須加 X 鎖,直到 T 結束才釋放鎖。

  能夠解決丟失修改問題,由於不能同時有兩個事務對同一個數據進行修改,那麼事務的修改就不會被覆蓋。

  ②二級封鎖協議【X鎖住不能讀數據】-讀髒數據

  在一級的基礎上,要求讀取數據 A 時必須加 S 鎖,讀取完立刻釋放 S 鎖。

  能夠解決讀髒數據問題,由於若是一個事務在對數據 A 進行修改,根據 1 級封鎖協議,會加 X 鎖,那麼就不能再加 S 鎖了,也就是不會讀入數據。

  ③三級封鎖協議【S鎖住防止數據變化】-不可重複讀

  在二級的基礎上,要求讀取數據 A 時必須加 S 鎖,直到事務結束了才能釋放 S 鎖。

  能夠解決不可重複讀的問題,由於讀 A 時,其它事務不能對 A 加 X 鎖,從而避免了在讀的期間數據發生改變。

1.5.2 兩段鎖協議【加鎖與解鎖】

  加鎖和解鎖分爲兩個階段進行。

  可串行化調度是指,經過併發控制,使得併發執行的事務結果與某個串行執行的事務結果相同。

  事務遵循兩段鎖協議是保證可串行化調度的充分條件。例如如下操做知足兩段鎖協議,它是可串行化調度。

  lock-x(A)...lock-s(B)...lock-s(C)...unlock(A)...unlock(C)...unlock(B)

  但不是必要條件,例如如下操做不知足兩段鎖協議,可是它仍是可串行化調度。

  lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(C)...unlock(C)

1.5.3 MySQL 隱式與顯示鎖定【InnoDB默認隱式】

  MySQL 的 InnoDB 存儲引擎採用兩段鎖協議,會根據隔離級別在須要的時候自動加鎖,而且全部的鎖都是在同一時刻被釋放,這被稱爲隱式鎖定。

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

  SELECT ... LOCK In SHARE MODE;   SELECT ... FOR UPDATE;

1.6 隔離級別

未提交讀(READ UNCOMMITTED)【讀-未提交】

  事務中的修改,即便沒有提交,對其它事務也是可見的。

提交讀(READ COMMITTED)【讀-已提交】

  一個事務只能讀取已經提交的事務所作的修改。換句話說,一個事務所作的修改在提交以前對其它事務是不可見的。

可重複讀(REPEATABLE READ)

  保證在同一個事務中屢次讀取一樣數據的結果是同樣的。

可串行化(SERIALIZABLE)【串行隔離性必定可以知足!!!】

  強制事務串行執行。

  須要加鎖實現,而其它隔離級別一般不須要。

1.7 多版本併發控制【解決讀未提交和讀已提交】

  多版本併發控制(Multi-Version Concurrency Control, MVCC)是 MySQL 的 InnoDB 存儲引擎實現隔離級別的一種具體方式,用於實現提交讀和可重複讀這兩種隔離級別。而未提交讀隔離級別老是讀取最新的數據行,無需使用 MVCC。可串行化隔離級別須要對全部讀取的行都加鎖,單純使用 MVCC 沒法實現。

版本號

  • 系統版本號:是一個遞增的數字,每開始一個新的事務,系統版本號就會自動遞增。
  • 事務版本號:事務開始時的系統版本號。

隱藏的列

MVCC 在每行記錄後面都保存着兩個隱藏的列,用來存儲兩個版本號:【系統還原操做的鏡像】

  • 建立版本號:指示建立一個數據行的快照時的系統版本號;
  • 刪除版本號:若是該快照的刪除版本號大於當前事務版本號表示該快照有效,不然表示該快照已經被刪除了。

如下實現過程針對可重複讀隔離級別。

當開始一個事務時,該事務的版本號確定大於當前全部數據行快照的建立版本號,理解這一點很關鍵。數據行快照的建立版本號是建立數據行快照時的系統版本號,系統版本號隨着建立事務而遞增,所以新建立一個事務時,這個事務的系統版本號比以前的系統版本號都大,也就是比全部數據行快照的建立版本號都大。

快照讀與當前讀

1. 快照讀

使用 MVCC 讀取的是快照中的數據,這樣能夠減小加鎖所帶來的開銷。

select * from table ...;

2. 當前讀

讀取的是最新的數據,須要加鎖。如下第一個語句須要加 S 鎖,其它都須要加 X 鎖。

select * from table where ? lock in share mode; select * from table where ? for update; insert; update; delete;

Next-Key Locks【相似於鎖定了一個範圍數據-解決幻影讀問題】

Next-Key Locks 是 MySQL 的 InnoDB 存儲引擎的一種鎖實現。

MVCC 不能解決幻影讀問題,Next-Key Locks 就是爲了解決這個問題而存在的。在可重複讀(REPEATABLE READ)隔離級別下,使用 MVCC + Next-Key Locks 能夠解決幻讀問題。

Record Locks

鎖定一個記錄上的索引,而不是記錄自己。

若是表沒有設置索引,InnoDB 會自動在主鍵上建立隱藏的聚簇索引,所以 Record Locks 依然可使用。

Gap Locks

鎖定索引之間的間隙,可是不包含索引自己。例如當一個事務執行如下語句,其它事務就不能在 t.c 中插入 15。

SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;

Next-Key Locks

它是 Record Locks 和 Gap Locks 的結合,不只鎖定一個記錄上的索引,也鎖定索引之間的間隙。例如一個索引包含如下值:10, 11, 13, and 20,那麼就須要鎖定如下區間:

(-∞, 10] (10, 11] (11, 13] (13, 20] (20, +∞)
 

2,關係數據庫設計理論

2.1 函數依賴【徹底依賴、部分依賴、傳遞依賴】

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

若是 {A1,A2,... ,An} 是關係的一個或多個屬性的集合,該集合函數決定了關係的其它全部屬性而且是最小的,那麼該集合就稱爲鍵碼。

對於 A->B,若是能找到 A 的真子集 A',使得 A'-> B,那麼 A->B 就是部分函數依賴,不然就是徹底函數依賴。

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

2.2 異常【插入、刪除、冗餘、修改】--致使數據非理想變化

如下的學生課程關係的函數依賴爲 {Sno, Cname} -> {Sname, Sdept, Mname, Grade},鍵碼爲 {Sno, Cname}。也就是說,肯定學生和課程以後,就能肯定其它信息。

Sno Sname Sdept Mname Cname Grade
1 學生-1 學院-1 院長-1 課程-1 90
2 學生-2 學院-2 院長-2 課程-2 80
2 學生-2 學院-2 院長-2 課程-1 100
3 學生-3 學院-2 院長-2 課程-2 95

不符合範式的關係,會產生不少異常,主要有如下四種異常:

  • 冗餘數據:例如 學生-2 出現了兩次。
  • 修改異常:修改了一個記錄中的信息,可是另外一個記錄中相同的信息卻沒有被修改。
  • 刪除異常:刪除一個信息,那麼也會丟失其它信息。例如刪除了 課程-1 須要刪除第一行和第三行,那麼 學生-1 的信息就會丟失。
  • 插入異常:例如想要插入一個學生的信息,若是這個學生還沒選課,那麼就沒法插入。
  • 範式

    範式理論是爲了解決以上提到四種異常。

    高級別範式的依賴於低級別的範式,1NF 是最低級別的範式。

第一範式:原子性;第二範式:去除部分依賴;第三範式:去除傳遞依賴;BC範式:去除主屬性內依賴;第四範式:去除多對多關係

第一範式:原子性、不可分【碼爲(id和課名)-部分依賴】

 

第二範式:在第一範式的基礎上去除部分依賴

 

第三範式:在第二範式的基礎上去除繼承依賴

其餘範式

BC範式(BCNF):符合3NF,而且,主屬性不依賴於主屬性。若關係模式R屬於第一範式,且每一個屬性都不傳遞依賴於鍵碼,則R屬於BC範式。
第四範式:要求把同一表內的多對多關係刪除。
第五範式:從最終結構從新創建原始結構。

3,ER 圖【實體關係圖】

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

用來進行關係型數據庫系統的概念設計。

實體的三種聯繫

包含一對一,一對多,多對多三種。

  • 若是 A 到 B 是一對多關係,那麼畫個帶箭頭的線段指向 B;
  • 若是是一對一,畫兩個帶箭頭的線段;
  • 若是是多對多,畫兩個不帶箭頭的線段。

下圖的 Course 和 Student 是一對多的關係。

表示出現屢次的關係

  一個實體在聯繫出現幾回,就要用幾條線鏈接。

  下圖表示一個課程的先修關係,先修關係出現兩個 Course 實體,第一個是先修課程,後一個是後修課程,所以須要用兩條線來表示這種關係。

聯繫的多向性

  雖然老師能夠開設多門課,而且能夠教授多名學生,可是對於特定的學生和課程,只有一個老師教授,這就構成了一個三元聯繫。

表示子類

  用一個三角形和兩條線來鏈接類和子類,與子類有關的屬性和聯繫都連到子類上,而與父類和子類都有關的連到父類上。

 

 

 

參考連接:

http://www.javashuo.com/article/p-fjxuozoj-ha.html

https://github.com/CyC2018/CS-Notes/blob/master/notes/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F%E5%8E%9F%E7%90%86.md

相關文章
相關標籤/搜索