天天看點

【Java崗】——資料庫引擎、資料庫範式、事務的四大特性ACID

作者:程式員小橙

Mysql資料庫引擎

【Java崗】——資料庫引擎、資料庫範式、事務的四大特性ACID

(1)、ISAM:該引擎在讀取資料方面速度很快,而且不占用大量的記憶體和存儲資源;但是ISAM不支援事務處理、不支援外鍵、不能夠容錯、也不支援索引。該引擎在包括MySQL 5.1及其以上版本的資料庫中不再支援。

(2)、MyISAM存儲引擎:mysql預設的引擎(mysql 5.1版本以前),不支援事務、也不支援行級鎖和外鍵。是以當執行Insert插入和Update更新語句時,即執行寫操作的時候需要鎖定這個表,是以會導緻效率會降低。它優勢是通路速度快,對事務完整性沒有要求,和Innodb相比,MyIASM引擎是儲存了表的行數,于是當進行select count(*) from table語句時,可以直接的讀取已經儲存的值而不需要進行掃描全表。以select,insert為主的應用基本上可以用這個引擎來建立表。

  支援3種不同的存儲格式,分别是:靜态表;動态表;壓縮表。

  靜态表:表中的字段都是非變長字段,這樣每個記錄都是固定長度的,優點是存儲非常迅速,容易緩存,出現故障容易恢複;缺點是占用的空間通常比動态表多(因為存儲時會按照列的寬度定義補足空格)ps:在取資料的時候,預設會把字段後面的空格去掉,如果不注意會把資料本身帶的空格也會忽略。

  動态表:記錄不是固定長度的,這樣存儲的優點是占用的空間相對較少;缺點:頻繁的更新、删除資料容易産生碎片,需要定期執行OPTIMIZE TABLE或者myisamchk-r指令來改善性能。

  壓縮表:因為每個記錄是被單獨壓縮的,是以隻有非常小的通路開支。

  (3)、InnoDB存儲引擎(在新版本的mysql中成為預設存儲引擎):Innodb引擎提供了對資料庫ACID事務的支援。并且還提供了行級鎖和外鍵的限制,以及自動增長列的支援。它的設計的目标就是處理大資料容量的資料庫系統。它本身實際上是基于Mysql背景的完整的系統。Mysql運作的時候,Innodb會在記憶體中建立緩沖池,用于緩沖資料和索引。但是,該引擎是不支援全文搜尋的。同時,啟動也比較的慢,它是不會儲存表的行數的。對比MyISAM引擎,寫的處理效率會差一些,并且會占用更多的磁盤空間以保留資料和索引。

  (4)、MEMORY存儲引擎:Memory存儲引擎使用存在于記憶體中的内容來建立表。每個memory表隻實際對應一個磁盤檔案,格式是.frm。memory類型的表通路非常的快,因為它的資料是放在記憶體中的,并且預設使用HASH索引,但是一旦服務關閉,表中的資料就會丢失掉。

  MEMORY存儲引擎的表可以選擇使用BTREE索引或者HASH索引,兩種不同類型的索引有其不同的使用範圍:

  Hash索引優點:Hash 索引結構的特殊性,其檢索效率非常高,索引的檢索可以一次定位,不像B-Tree索引需要從根節點到枝節點,最後才能通路到葉節點這樣多次的IO通路,是以 Hash 索引的查詢效率要遠高于 B-Tree 索引;

  Hash索引缺點:那麼不精确查找呢,也很明顯,因為hash算法是基于等值計算的,是以對于“like”等範圍查找hash索引無效,不支援。

  Memory類型的存儲引擎主要用于那些内容變化不頻繁的代碼表,或者作為統計操作的中間結果表,便于高效地對中間結果進行分析并得到最終的統計結果。對存儲引擎為memory的表進行更新操作要謹慎,因為資料并沒有實際寫入到磁盤中,是以一定要對下次重新啟動服務後如何獲得這些修改後的資料有所考慮。

  (5)、MERGE存儲引擎:Merge存儲引擎是一組MyISAM表的組合,這些MyISAM表必須結構完全相同,merge表本身并沒有資料,對merge類型的表可以進行查詢,更新,删除操作,這些操作實際上是對内部的MyISAM表進行的。

MyISAM和InnoDB的差別

  Mysql5.1之前的預設引擎是MyISAM,mysql5.1之後的預設引擎是InnoDB。

  1、事務處理上方面

  MyISAM 強調的是性能,查詢的速度比 InnoDB 類型更快,但是不提供事務支援。InnoDB 提供事務支援。

  2、表主鍵

  MyISAM:允許沒有主鍵的表存在。InnoDB:如果沒有設定主鍵,就會自動生成一個 6 位元組的主鍵(使用者不可見)。

  3、外鍵

  MyISAM 不支援外鍵,InnoDB 支援外鍵。

  4、全文索引

  MyISAM 支援全文索引,InnoDB 不支援全文索引。innodb 從 mysql 5.6 版本開始提供對全文索引的支援。

  5、鎖

  MyISAM 隻支援表級鎖,InnoDB 支援行級鎖和表級鎖,預設是行級鎖,行鎖大幅度提高了多使用者并發操作的性能。innodb 比較适合于插入和更新操作比較多的情況,而 myisam 則适合用于頻繁查詢的情況。另外,InnoDB 表的行鎖也不是絕對的,如果在執行一個 SQL 語句時,MySQL 不能确定要掃描的範圍,InnoDB 表同樣會鎖全表,例如 update table set num=1 where name like “%aaa%”。

  6、表的具體行數

  MyISAM:select count(*) from table,MyISAM 隻要簡單的讀出儲存好的行數。因為MyISAM 内置了一個計數器,count(*)時它直接從計數器中讀。

  InnoDB:不儲存表的具體行數,也就是說,執行 select count(*) from table 時,InnoDB要掃描一遍整個表來計算有多少行。  

資料庫範式

  資料庫的“範式”,指的是設計資料庫的規則。按照一定的規則設計出資料庫的表和關系,能夠避免在一些情況下的查詢出錯,并具有良好的結構。總的來說,随着範式等級的提高,資料表屬性之間的依賴關系越來越小,資料備援越來越低。但同時,資料關系變得更加複雜,通路一個具體資料的關系層次增加。是以像設計模式一樣,不應盲目追求範式等級,應根據具體需求來選擇範式。

  幾個概念:

  1、超鍵(super key):能夠唯一辨別一條記錄的屬性或屬性集。

  2、候選鍵(candidate key):能夠唯一辨別一條記錄的最小屬性集,候選鍵是沒有多餘屬性的超鍵,候選鍵可能有多個。

  3、主鍵(主碼、primary key):某個能夠唯一辨別一條記錄的最小屬性集,選取某個候選鍵為主鍵。

  4、外鍵(foreign key):子資料表中出現的父資料表的主鍵,稱為子資料表的外鍵。

  5、代理鍵:當不适合用任何一個候選鍵作為主鍵時(如資料太長等),添加一個沒有實際意義的鍵作為主鍵,這個鍵就是代理鍵。(如常用的序号1、2、3)

  部分函數依賴:設X,Y是關系R的兩個屬性集合,存在X→Y,若X’是X的真子集,存在X’→Y,則稱Y部分函數依賴于X。

  舉個例子:學生基本資訊表R中(學号,身份證号,姓名)當然學号屬性取值是唯一的,在R關系中,(學号,身份證号)->(姓名),(學号)->(姓名),(身份證号)->(姓名);是以姓名部分函數依賴與(學号,身份證号);

  完全函數依賴:設X,Y是關系R的兩個屬性集合,X’是X的真子集,存在X→Y,但對每一個X’都有X’!→Y,則稱Y完全函數依賴于X。

  例子:學生基本資訊表R(學号,班級,姓名)假設不同的班級學号有相同的,班級内學号不能相同,在R關系中,(學号,班級)->(姓名),但是(學号)->(姓名)不成立,(班級)->(姓名)不成立,是以姓名完全函數依賴與(學号,班級);

  傳遞函數依賴:設X,Y,Z是關系R中互不相同的屬性集合,存在X→Y(Y !→X),Y→Z,則稱Z傳遞函數依賴于X。

  例子:在關系R(學号,宿舍,費用)中,(學号)->(宿舍),宿舍!=學号,(宿舍)->(費用),費用!=宿舍,是以符合傳遞函數的要求;

【Java崗】——資料庫引擎、資料庫範式、事務的四大特性ACID

 第一範式(1NF):每一個屬性都不能再分割,都是原子項。

  說明:在任何一個關系資料庫中,第一範式(1NF)是對關系模式的基本要求,不滿足第一範式(1NF)的資料庫就不是關系資料庫。減少了資料的備援,節省存儲空間,某些情況下減少了資料通路的層數,提高資料通路速度。

  第二範式(2NF):滿足第一範式,非主鍵屬性均完全依賴于主鍵,不能隻是部分依賴主鍵。

  2NF消除了屬性對主鍵的部分函數依賴。可以在一定程度上消除備援,節省存儲空間。如果存在部分函數依賴,則可能存在資料備援。在多條記錄中,主鍵中的某一個屬性可能是一樣的,而如果有其他資料項函數依賴于這個不變的屬性,則這些資料項也将是一樣的。

  第三範式(3NF):滿足第一、二範式,要求每列都與主鍵有直接關系,不存在傳遞依賴。所有非主鍵屬性之間沒有函數依賴關系。

  既然存在函數依賴,某些資料項就能夠通過其他資料項計算得出,很可能存在資料備援。值得注意的是,在一些情況下,存在這種資料備援有意義的。如果在表格中存儲着某些運算的結果,我們在使用這些結果時就不用進行運算了,節省了運算時間,是一種“空間換時間”的做法。從這裡也可以看出,應用範式并不能夠保證最好的效果,需要根據應用需求進行合理取舍。

  BC範式(boyce-codd範式,BCNF):滿足1NF、2NF、3NF,所有屬性(包含主鍵屬性和非鍵主屬性)都不傳遞依賴于任何候選鍵。

  BC範式在3NF的基礎上,要求主鍵屬性也不能傳遞依賴于任何候選鍵。當主鍵是複合鍵時,主鍵的某個屬性可能會依賴于某個候選鍵。此時,關系能夠符合3NF,因為并不是“非主鍵”屬性依賴于某個非主鍵屬性。但此關系并不符合BC範式。

  第四範式:要求把同一表内的多對多關系删除。(表中不能包含一個實體的兩個或多個多值屬性)

  所謂多值屬性,指的是某個屬性可以包含多個值。這個屬性的(多個)取值,被另一個屬性決定。也就是說,一旦确定了某個屬性,另一個屬性的多個取值就一起确定了。第四範式在第三範式的基礎上,消除多值依賴。(一個表隻允許一個多值依賴),消除了多值依賴,可以降低資料備援,增删改都簡單了,減少資料處理複雜度。

  第五範式:滿足1NF、2NF、3NF、4NF,如果将表中的多元關系分解成一個一個的二進制關系,一定會丢失資訊。

  第五範式在4NF的基礎上,進一步消除依賴。第五範式的要求明确,如果不用這個表就不能正确說明資料之間的聯系。是以符合5NF的表已經沒有任何多餘依賴的存在了。是以第五範式是一個比較理想的範式。

資料庫事務的四大特性(ACID)

  如果一個資料庫聲稱支援事務的操作,那麼該資料庫必須要具備以下四個特性:

  1、原子性(Atomicity)

  原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗復原,是以事務的操作如果成功就必須要完全應用到資料庫,如果操作失敗則不能對資料庫有任何影響。

  2、一緻性(Consistency)

  一緻性是指事務必須使資料庫從一個一緻性狀态變換到另一個一緻性狀态,也就是說一個事務執行之前和執行之後都必須處于一緻性狀态。

  拿轉賬來說,假設使用者A和使用者B兩者的錢加起來一共是5000,那麼不管A和B之間如何轉賬,轉幾次賬,事務結束後兩個使用者的錢相加起來應該還得是5000,這就是事務的一緻性。

  3、隔離性(Isolation)

  隔離性是當多個使用者并發通路資料庫時,比如操作同一張表時,資料庫為每一個使用者開啟的事務,不能被其他事務的操作所幹擾,多個并發事務之間要互相隔離。

  即要達到這麼一種效果:對于任意兩個并發的事務T1和T2,在事務T1看來,T2要麼在T1開始之前就已經結束,要麼在T1結束之後才開始,這樣每個事務都感覺不到有其他事務在并發地執行。

  4、持久性(Durability)

  持久性是指一個事務一旦被送出了,那麼對資料庫中的資料的改變就是永久性的,即便是在資料庫系統遇到故障的情況下也不會丢失送出事務的操作。

  例如我們在使用JDBC操作資料庫時,在送出事務方法後,提示使用者事務操作完成,當我們程式執行完成直到看到提示後,就可以認定事務已經正确送出,即使這時候資料庫出現了問題,也必須要将我們的事務完全執行完成,否則就會造成我們看到提示事務處理完畢,但是資料庫因為故障而沒有執行事務的重大錯誤。

 現在重點來說明下事務的隔離性,當多個線程都開啟事務操作資料庫中的資料時(并發事務),資料庫系統要能進行隔離操作,以保證各個線程擷取資料的準确性,在介紹資料庫提供的各種隔離級别之前,我們先看看如果不考慮事務的隔離性,會發生的幾種問題:

  1、更新丢失

  兩個事務T1和T2讀入同一資料并修改,T2送出的結果覆寫了T1送出的結果,導緻T1的修改被丢失。

  2、髒讀

  髒讀是指在一個事務處理過程裡讀取了另一個未送出的事務(或者事務由于某種原因被撤銷)中的資料。

  當一個事務正在多次修改某個資料,而在這個事務中這多次的修改都還未送出,這時一個并發的事務來通路該資料,就會造成兩個事務得到的資料不一緻。例如:使用者A向使用者B轉賬100元,對應SQL指令如下:

  update account set money = money + 100 where name = ’B’;(此時A通知B)

  update account set money = money - 100 where name = ’A’;

  當隻執行第一條SQL時,A通知B檢視賬戶,B發現确實錢已到賬(此時即發生了髒讀),而之後無論第二條SQL是否執行,隻要該事務不送出,則所有操作都将復原,那麼當B以後再次檢視賬戶時就會發現錢其實并沒有轉。

  3、不可重複讀

  不可重複讀是指在對于資料庫中的某個資料,一個事務範圍内多次查詢卻傳回了不同的資料值,這是由于在查詢間隔,被另一個事務修改并送出了。

  例如事務T1在讀取某一資料,而事務T2立馬修改了這個資料并且送出事務給資料庫,事務T1再次讀取該資料就得到了不同的結果,發送了不可重複讀。

  不可重複讀和髒讀的差別是,髒讀是某一事務讀取了另一個事務未送出的髒資料,而不可重複讀則是讀取了前一事務送出的資料。

  4、虛讀(幻讀)

  幻讀是事務非獨立執行時發生的一種現象。例如事務T1對一個表中所有的行的某個資料項做了從“1”修改為“2”的操作,這時事務T2又對這個表中插入了一行資料項,而這個資料項的數值還是為“1”并且送出給資料庫。而操作事務T1的使用者如果再檢視剛剛修改的資料,會發現還有一行沒有修改,其實這行是從事務T2中添加的,就好像産生幻覺一樣,這就是發生了幻讀。

  幻讀和不可重複讀都是讀取了另一條已經送出的事務(這點就髒讀不同),所不同的是不可重複讀查詢的都是同一個資料項,而幻讀針對的是一批資料整體(比如資料的個數)。

  現在來看看MySQL資料庫為我們提供的四種隔離級别:

  ①、Serializable(串行化):可避免髒讀、不可重複讀、幻讀的發生。

  ②、Repeatable read(可重複讀):可避免髒讀、不可重複讀的發生。

  ③、Read committed(讀已送出):可避免髒讀的發生。

  ④、Read uncommitted (讀未送出):最低級别,任何情況都無法保證。

  以上四種隔離級别最高的是Serializable級别,最低的是Read uncommitted級别,當然級别越高,執行效率就越低。像Serializable這樣的級别,就是以鎖表的方式(類似于Java多線程中的鎖)使得其他的線程隻能在鎖外等待,是以平時選用何種隔離級别應該根據實際情況。在MySQL資料庫中預設的隔離級别為Repeatable read(可重複讀)。

繼續閱讀