3分鐘了解InnoDB鎖機制與事務隔離

鎖機制

共享排他鎖

InnoDB實現(xiàn)了兩種標準行級鎖

  • 共享鎖(S)
    持有S鎖的事務可以讀取行
  • 排他鎖(X)
    持有X鎖的事務可以修改或者刪除行

共享鎖與排他鎖的兼容性:

S X
S 兼容 互斥
X 互斥 互斥

即:

  1. 多個事務可以同時獲取S鎖,讀讀可以并行
  2. 只有一個事務能夠獲取X鎖坞生,寫寫不能并行
  3. 一條記錄要么是S鎖要么是X鎖,讀寫不能并行

意向鎖

意向鎖是表級鎖,它表明一個事務需要在這個表的行上添加的鎖類型。

意向鎖有兩種:

  • 意向共享鎖(IS)
    表明一個事務有意向表中的行添加S鎖,加鎖方式SELECT …… LOCK IN SHARE MODE
  • 意向排他鎖(IX)
    表明一個事務有意向表中的行添加X鎖誓焦,加鎖方式 SELECT …… FOR UPDATE

意向鎖的協(xié)議:

  • 一個事務獲取S鎖之前,必須獲取IS鎖
  • 一個事務獲取X鎖之前着帽,必須獲取IX鎖

意向鎖與共享排他鎖的兼容性:

S IS X IX
S 兼容 兼容 互斥 互斥
IS 兼容 兼容 互斥 兼容
X 互斥 互斥 互斥 互斥
IX 互斥 兼容 互斥 兼容

記錄鎖杂伟、間隙鎖、臨鍵鎖

假設有一張表:

id name no
1 dxy1 10
2 dxy2 20
3 dxy3 30

PK:id
Key:name
Key:no

  • 記錄鎖
    記錄鎖是對記錄行加鎖仍翰,只對主鍵或者唯一索引生效稿壁,并且必須是精確匹配
    例如:
    事務A先執(zhí)行,不提交:
    select * from t where id = 1 for update;
    事務B后執(zhí)行:
    select * from t where id = 1 for update;
    如圖歉备,事務B阻塞傅是,因為id=1的記錄已經有了記錄鎖
  • 間隙鎖
    間隙鎖是一種開區(qū)間鎖,用來解決插入的問題
    例如:
    事務A先執(zhí)行蕾羊,不提交:
    select * from t where id between 1 and 10 for update;
    事務B后執(zhí)行:
    insert into t values(8,'dxy8',8);

如圖:事務B阻塞喧笔,因為區(qū)間(1,10)已經加鎖


  • 臨鍵鎖
    臨鍵鎖是由記錄鎖以及索引記錄之前的間隙組成
    例如:
    事務A先執(zhí)行龟再,不提交:
    select * from t where no = 20 for update;
    事務B后執(zhí)行:
    insert into t values(19,'dxy19',19);
    如圖:事務B被阻塞书闸,因為區(qū)間(10,20]已經加鎖

需要注意的是

  1. 如果no是唯一索引利凑,那么事務A支持有id=20的記錄鎖
  2. 如果no是普通索引浆劲,那么會持有(10,20]的臨鍵鎖和(20,30)的間隙鎖

插入意向鎖

插入意向鎖是一種特殊的間隙鎖,由插入操作設置
多個事務插入記錄哀澈,如果在同一區(qū)間內插入位置不沖突牌借,那么不會相互阻塞

例如:

id name no
1 dxy1 10
2 dxy2 20
3 dxy3 30

事務A先執(zhí)行,不提交:
insert into t values(11,'dxy11',11);
事務B后執(zhí)行:
insert into t values(12,'dxy12',12);
事務B不會被阻塞

但是如果事務B執(zhí)行:
insert into t values(11,'dxy11',11);
如圖:事務B依然會被阻塞割按,因為事務A占有記錄鎖

自增鎖

自增鎖是一種特殊的表級鎖膨报,是由向包含自增列的表中插入數(shù)據(jù)的事務獲取的。
注意:自增鎖的生命周期就是一條語句,而不是事務
例如:
事務A先執(zhí)行现柠,不提交:
insert into t(name,no) values('dxy11',11),('dxy12',12);
事務B后執(zhí)行院领,不提交:
insert into t(name,no) values('dxy13',13);
事務A后執(zhí)行,不提交:
insert into t(name,no) values('dxy14',14);

如圖:事務A兩條語句插入的記錄够吩,id是不連續(xù)的

可以通過innodb_autoinc_lock_mode設置自增鎖模式:

  1. innodb_autoinc_lock_mode=0(傳統(tǒng)鎖模型)
  2. innodb_autoinc_lock_mode=1(連續(xù)鎖模型)
  3. innodb_autoinc_lock_mode=2(交叉鎖模型)
    更多關于自增鎖模式的描述比然,參考官網(wǎng)文檔

事務隔離性

我們知道事務有ACID四大特性,其中I就是代表的隔離性(isotation)
什么是事務的隔離性周循?
隔離性是指多個事務并發(fā)訪問同一個表數(shù)據(jù)時谈秫,一個事務不會受到另一個事務對數(shù)據(jù)操作的影響。

并發(fā)事務之間的干擾存在哪些問題鱼鼓?
假設表t有數(shù)據(jù):

id name no
1 dxy1 10
  • 場景1

事務A先執(zhí)行拟烫,不提交:
insert into t values(4,'dxy11',11);

事務B后執(zhí)行,不提交:
select * from t;

id name no
1 dxy1 10
4 dxy11 11

最后事務A回滾

此時迄本,事務B就讀取并處理了一條不存在的數(shù)據(jù)硕淑,這種情況就是臟讀

  • 場景2

事務A先執(zhí)行,不提交:
select * from t where id >= 1;

id name no
1 dxy1 10

事務B后執(zhí)行嘉赎,并提交:
update t set name = 'wuming' where id = 1;

事務A再次執(zhí)行:
select * from t where id >= 1;

id name no
1 wuming 10

此時置媳,事務A先后兩次查詢的記錄數(shù)不一致,這種情況就是不可重復讀

  • 場景3

事務A先執(zhí)行公条,不提交:
select * from t where id = 1;

id name no
1 dxy1 10

事務B后執(zhí)行拇囊,并提交:
insert into t values(4,'dxy11',11);

事務A再次執(zhí)行:
select * from t where id = 1;

id name no
1 dxy1 10
4 dxy11 11

此時,事務A先后兩次查詢的記錄數(shù)不一致靶橱,這種情況就是幻讀

因此寥袭,并發(fā)事務可能導致

  1. 臟讀:一個事務讀取了另一個事務未提交的數(shù)據(jù)
  2. 不可重復讀:一個事務讀取了另一個事務修改并提交的數(shù)據(jù)
  3. 幻讀:一個事務讀取了另一個事務增加或刪除并提交的數(shù)據(jù)

為了平衡并發(fā)事務的性能和數(shù)據(jù)一致性、可靠性关霸、再現(xiàn)性传黄,InnoDB支持了SQL:1992表準中全部四種隔離級別

  1. 讀未提交(Read Uncommitted)
    Select語句不加鎖,事務可能讀取其他事務未提交的數(shù)據(jù)队寇,即臟讀膘掰。因此,這種級別的并發(fā)性最好佳遣,一致性最差

  2. 讀已提交(Read Committed)

    • 對于非加鎖讀识埋,每次都讀取最新的快照
    • 對于加鎖讀、更新零渐、刪除窒舟,只對記錄加鎖而不對間隙加鎖,即這種級別不支持間隙鎖相恃,因此會導致幻讀

    因此辜纲,RC的隔離級別會出現(xiàn)不可重復讀和幻讀

  3. 可重復讀(Repeatable Read)(默認級別)

    • 對于非加鎖讀,同一個事務只在第一次查詢時生成快照拦耐。
    • 對于加鎖讀耕腾、更新、刪除存在兩種情況
      1. 唯一索引精確匹配:只對數(shù)據(jù)加記錄鎖
      2. 范圍查詢或非唯一索引:使用間隙鎖和臨鍵鎖

    因此杀糯,RR級別下可以完全避免幻影行和不可重復讀

  4. 序列化(Serializable)
    最嚴格的隔離級別扫俺,所有select全部轉換成 select …… lock in share mode。這就導致固翰,如果其他事務修改記錄狼纬,那么select會被阻塞。

全表掃描在RC和RR級別下的加鎖策略是怎樣的呢骂际?
假設有一張表t:

id name no
1 dxy1 10
2 dxy2 20
  • RR級別
    事務A先執(zhí)行疗琉,不提交:
    select * from t where no = 10 for update;
    事務B后執(zhí)行:
    select * from t where no = 20 for update
    如圖:事務B被阻塞,因為RR級別下會對所有掃描的數(shù)據(jù)加鎖
  • RC級別
    事務A先執(zhí)行歉铝,不提交:
    select * from t where no = 10 for update;
    事務B后執(zhí)行:
    select * from t where no = 20 for update
    如圖:事務B不會被阻塞盈简,因為只會對no=10的行加鎖
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市太示,隨后出現(xiàn)的幾起案子柠贤,更是在濱河造成了極大的恐慌,老刑警劉巖类缤,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件臼勉,死亡現(xiàn)場離奇詭異,居然都是意外死亡餐弱,警方通過查閱死者的電腦和手機宴霸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膏蚓,“玉大人猖败,你說我怎么就攤上這事〗翟剩” “怎么了恩闻?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長剧董。 經常有香客問我幢尚,道長,這世上最難降的妖魔是什么翅楼? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任尉剩,我火速辦了婚禮,結果婚禮上毅臊,老公的妹妹穿的比我還像新娘理茎。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布皂林。 她就那樣靜靜地躺著朗鸠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪础倍。 梳的紋絲不亂的頭發(fā)上烛占,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音沟启,去河邊找鬼忆家。 笑死,一個胖子當著我的面吹牛德迹,可吹牛的內容都是我干的芽卿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼胳搞,長吁一口氣:“原來是場噩夢啊……” “哼蹬竖!你這毒婦竟也來了?” 一聲冷哼從身側響起流酬,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤币厕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后芽腾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旦装,經...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年摊滔,在試婚紗的時候發(fā)現(xiàn)自己被綠了阴绢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡艰躺,死狀恐怖呻袭,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情腺兴,我是刑警寧澤左电,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站页响,受9級特大地震影響篓足,放射性物質發(fā)生泄漏。R本人自食惡果不足惜闰蚕,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一栈拖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧没陡,春花似錦涩哟、人聲如沸索赏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潜腻。三九已至,卻和暖如春锻弓,著一層夾襖步出監(jiān)牢的瞬間砾赔,已是汗流浹背蝌箍。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工青灼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人妓盲。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓杂拨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親悯衬。 傳聞我的和親對象是個殘疾皇子弹沽,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容