鎖模塊之MyISAM與InnoDB關於鎖方面的區別


鎖模塊

常見問題

  1. MyISAM與InnoDB關於鎖方面的區別是什么
  2. 數據庫事物的四大特性
  3. 事物隔離級別以及各級別下的並發問題

一、MyISAM與InnoDB關於鎖方面的區別是什么

  • MyISAM默認用的是表級鎖,不支持行級鎖
  • InnoDB默認用的是行級鎖,也支持表級鎖
  • InnoDB不支持FULLTEXT類型的索引
  • InnoDB中不保存表的具體行數,也就是說,執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行,但是MyISAM只要簡單的讀出保存好的行數即可。注意的是,當count(*)語句包含where條件時,兩種表的操作是一樣的。
  • 對於AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,但是在MyISAM表中,可以和其他字段一起建立聯合索引。
  • DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除。
  • LOAD TABLE FROM MASTER操作對InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,導入數據后再改成InnoDB表,但是對於使用的額外的InnoDB特性(例如外鍵)的表不適用。

MyISAM引擎

創建表

  CREATE TABLE `person_info_myisam`(

  `id` int(7) NOT NULL AUTO_INCREMENT,

  `account` varchar(10) DEFAULT NULL,

  `name` varchar(20) DEFAULT NULL,

  `area` varchar(20) DEFAULT NULL,

  `title` varchar(20) DEFAULT NULL,

  `motto` varchar(50) DEFAULT NULL,

  PRIMARY KEY `id` ,

  UNIQUE KEY `account` (`account`),

  KEY `index_area_title` (`area`,`title`)

  )  ENGINE=MYISAM DEFAULT CHARSET=utf8;

由於MYISAM不支持事物,所以模仿並發時,需要將表的數據量增加到兩千萬數據量來真實模擬並發訪問的場景,這樣MyISAM會給我們加上表級鎖。

  • 讀鎖與寫鎖互斥:打開一個session對表進行查詢"select * from person_info_myisam where id between 1 and 20000000;",由於對表進行查詢是會對表加上一個表級的讀鎖。在查詢未結束時,再打開一個session對表進行更新操作"update person_info_myisam set account=account where id=20000001",由於第一個session還未結束,讀鎖還未釋放,這時第二個session加入表級別寫鎖就會被阻塞,直到讀鎖釋放鎖。
  • 讀鎖是共享鎖:打開一個session對表進行查詢"select * from person_info_myisam where id between 1 and 20000000;",在查詢未結束時,也就是當前session未釋放讀鎖時,再打開一個session對表進行查詢"select * from person_info_myisam where id =20000001 ;",此時第二個session並不會被阻塞。
  • 寫鎖是排他鎖:當第一個session對表加上寫鎖的時候,第二個session無論是對表進行讀還是寫,都必須等第一個session寫鎖釋放。
  • 如何對讀鎖加上排他鎖:在查詢語句后加上 for update,例如"select * from person_info_myisam where id between 1 and 20000000 for update;"

InnoDB引擎

創建表

  CREATE TABLE `person_info_Innodb`(

  `id` int(7) NOT NULL AUTO_INCREMENT,

  `account` varchar(10) DEFAULT NULL,

  `name` varchar(20) DEFAULT NULL,

  `area` varchar(20) DEFAULT NULL,

  `title` varchar(20) DEFAULT NULL,

  `motto` varchar(50) DEFAULT NULL,

  PRIMARY KEY `id` ,

  UNIQUE KEY `account` (`account`),

  KEY `index_area_title` (`area`,`title`)

  )  ENGINE=InnoDB DEFAULT CHARSET=utf8;

InnoDB是支持事物的,但是mysql當中事物是默認提交的,首先要關閉事物自動提交,使用"show variables like 'autocommit';"查看事物提交狀態,使用"set autocommit=0;"關閉自動提交

  • 讀鎖與寫鎖互斥:打開一個session對行進行查詢"select * from person_info_Innodb where id = 3 lock in share mode",由於InnoDB對select語句進行了優化,所以必須要加上 lock in share mode才可以對select進行加讀鎖,此時再打開一個session對該行進行更新"update person_info_Innodb set title='test3' where id=3;",此時這行就會被鎖住,需要第一個session進行commit提交之后,才可以執行更新。如果此時第二個session並不是對id=3的行進行更新而是對其他行進行更新,則不會被鎖住,由此證明InnoDB默認支持行級鎖
  • 讀鎖共享鎖:打開一個session對行進行查詢"select * from person_info_Innodb where id = 3 lock in share mode",再打開一個session對id=3的行進行加讀鎖"select * from person_info_Innodb where id = 3 lock in share mode",第二個session並不會阻塞。

以上操作都使用了id主鍵索引走的是行級鎖以及gap鎖,當不使用索引時,InnoDB走的是表級鎖。那么是不是行級鎖一定比表級鎖要好?那倒未必,鎖的粒度越細代價就越高,表級鎖是在表頭進行加鎖,行級鎖還要掃描到該行進行加鎖,這樣的代價比較大。

注意:

MyISAM適合的場景:

  • 頻繁執行全表count語句
  • 對數據進行增刪改的頻率不高,查詢非常頻繁
  • 沒有事物

InnoDB適合的場景:

  • 數據增刪改查都相當的頻繁
  • 可靠性要求比較高,要求支持事物

數據庫鎖的分類:

  • 按鎖的粒度划分,可分為表級鎖、行級鎖、頁級鎖
  • 按鎖的級別划分,可分為共享鎖、排他鎖
  • 按加鎖的方式划分,可分為自動鎖、顯示鎖
  • 按操作划分,可分為DML鎖,DDL鎖
  • 按使用方式划分,可分為樂觀鎖(在數據庫表中加一個列記錄當前數據的版本)、悲觀鎖(上述的MyISAM引擎和InnoDB引擎都是悲觀鎖)

二、數據庫事物的四大特性

ACID

  • 原子性(Atomic)
  • 一致性(Consistency)
  • 隔離性(Isolation)
  • 持久性(Durability)

三、事物隔離級別以及各級別下的並發訪問問題

mysql事物隔離級別的查看

select @@tx_isolation;

 

 

事物隔離級別以及設置

 

1)read uncommitted : 讀取尚未提交的數據 :哪個問題都不能解決
2)read committed:讀取已經提交的數據 :可以解決臟讀 ---- oracle默認的
3)repeatable read:重讀讀取:可以解決臟讀 和 不可重復讀 ---mysql默認的
4)serializable:串行化:可以解決 臟讀 不可重復讀 和 虛讀---相當於鎖表

 

 

 

 

設置

 

set session transaction isolation level 設置事務隔離級別

 

 

事物並發訪問引起的問題以及如何避免

  1. 更新丟失——mysql所有事物隔離級別在數據庫層面上均可避免
  2. 臟讀——READ-COMMITTED事物隔離級別以上可避免
    在數據庫隔離級別為read uncommitted 時會產生臟讀,臟讀會發生在一個事物A讀取了被另一個事物B修改,但還未提交的數據,則事物A讀取的是無效的數據,這跟不可重復讀類似,但是第二個事物不需要提交
    例如:
      peiqi的賬號有1000元,事物A往peiqi賬戶存200元,但未提交,與此同時
      事物B查詢peiqi的賬戶,這時讀取到peiqi賬戶有1200,隨后,
      事物A發生異常,而回滾了事物,peiqi的賬戶又變為1000。這時事物B讀取到peiqi的賬戶為1200即為臟數據,事物B做了一次臟讀
  3. 不可重復讀——REPEATABLE-READ事物隔離級別以上可避免
    在數據庫隔離級別為read committed及以下;這時在一個事物內,多次讀取同一數據,在這個事物還沒有結束時,另外一個事物也訪問該同一數據。那么,在第一個事物中的;兩次讀取數據之間,恰好這時又存在第二個事物對這個數據進行修改,那么第一個事物兩次讀取到的數據可能是不一樣的,這樣就發生了在同一個事物內兩次讀取到的數據是不一樣的,因此稱為是不可重復讀。
    例如:
      事物A中,讀取到peiqi的賬戶有1000元,操作沒有完成,事物還沒有提交,與此同時
      事物B在peiqi的賬戶增加了200元,並提交了事物,隨后
      事物A中,再次讀取peiqi的賬戶,此時賬戶已經變成了1200元,在同一個事物A中的兩次讀取的結果不一致,導致了不可重復讀。
  4. 幻讀——SERIALIZABLE事物隔離級別可避免
    幻讀是指當事物不是獨立執行時發生的一種現象,例如第一個事物對表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事物也修改這個表中的數據,這種修改是向表中插入一行新數據。那么,以后就會發生操作第一個事物的用戶發現表中還有沒有修改的數據行,就好像發生幻覺一樣。
    例如:
      目前工資為1000的員工有10人,事物A讀取所有工資為1000的人數為10人。此時,
      事物B插入一條工資也為1000的記錄。
      這時,事物A再次讀取工資為1000的員工,記錄為11人,此時產生了幻讀。

提醒:

不可重復讀的重點是修改,同樣的條件,你讀取過的數據,再次讀取出來發現值不一樣了

幻讀的重點是在於新增或者刪除,同樣的條件,第一次和第二次讀取出來的記錄數不一樣了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM