成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇帶給你MySQL鎖機(jī)制

數(shù)據(jù)庫(kù) MySQL
鎖按照鎖粒度分為:全局鎖、表鎖和行鎖。行鎖是引擎層的實(shí)現(xiàn),我們文中描述的行鎖都是基于InnoDB存儲(chǔ)引擎的實(shí)現(xiàn)。InnoDB的行鎖采用的兩階段鎖協(xié)議,鎖在需要的時(shí)候添加,只有在事務(wù)commit或者rollback時(shí)才會(huì)一次性釋放所有鎖。

無(wú)論什么時(shí)候,只要存在多個(gè)連接在同一時(shí)刻修改數(shù)據(jù),都會(huì)涉及到并發(fā)控制的問(wèn)題。MySQL實(shí)現(xiàn)了兩個(gè)層面的并發(fā)控制:服務(wù)層和引擎層。

鎖分類

按照使用場(chǎng)景分類

共享鎖:共享鎖(shared lock)也稱為讀鎖(read lock)。共享鎖是共享的,或者說(shuō)是相互不阻塞的。多個(gè)連接在同一時(shí)刻可以同時(shí)讀取同一個(gè)資源,而不相互干擾。

排他鎖:排他鎖(exclusive lock)也稱為寫鎖(write lock)。寫鎖是排他的,也就是一個(gè)寫鎖會(huì)阻塞其他的寫鎖和讀鎖。

按照加鎖思想分類

悲觀鎖:對(duì)數(shù)據(jù)被外界修改保持悲觀的態(tài)度,在整個(gè)數(shù)據(jù)處理過(guò)程中,數(shù)據(jù)都處于鎖定狀態(tài)。

樂(lè)觀鎖:它認(rèn)為數(shù)據(jù)一般情況下不會(huì)造成沖突,在數(shù)據(jù)更新的時(shí)候才會(huì)對(duì)數(shù)據(jù)的沖突與否進(jìn)行校驗(yàn)。

按照鎖粒度分類

全局鎖:對(duì)整個(gè)數(shù)據(jù)庫(kù)實(shí)例加鎖,它將整個(gè)數(shù)據(jù)庫(kù)實(shí)例處于只讀的狀態(tài)。

表級(jí)鎖:對(duì)整個(gè)表進(jìn)行加鎖的方式。MySQL表級(jí)鎖分為表鎖和元數(shù)據(jù)鎖。

行級(jí)鎖:行鎖可以最大程度的支持并發(fā)處理,行鎖是存儲(chǔ)引擎層實(shí)現(xiàn)的,而MySQL服務(wù)層并沒(méi)有實(shí)現(xiàn)行鎖。InnoDB存儲(chǔ)引擎行級(jí)鎖類型:Record Lock、Gap Lock、Next-key Lock。

讀寫鎖

讀鎖

共享鎖:共享鎖(shared lock)也稱為讀鎖(read lock)。共享鎖是共享的,或者說(shuō)是相互不阻塞的。多個(gè)連接在同一時(shí)刻可以同時(shí)讀取同一個(gè)資源,而不相互干擾。

加鎖命令

  1. select ...... lock in share mode; 

測(cè)試

測(cè)試時(shí),設(shè)置事務(wù)手動(dòng)提交:set autocommit = 0,后續(xù)如果沒(méi)有明確的提示,autocommit都是0。

測(cè)試時(shí),大家開啟兩個(gè)窗口,建立兩個(gè)連接,窗口1和窗口2分別對(duì)應(yīng)事務(wù)A和事務(wù)B。

  • 窗口1:查詢id=6的行數(shù)據(jù)并添加讀鎖,正確返回?cái)?shù)據(jù)。
  • 窗口2:依然查詢id=6的行數(shù)據(jù)并添加讀鎖,正確返回?cái)?shù)據(jù)。讀讀不沖突。
  • 窗口1:對(duì)id=6的行執(zhí)行寫操作(update語(yǔ)句),在窗口2的事務(wù)提交之前,寫操作阻塞,并可能會(huì)超時(shí)退出。

如果寫鎖等待時(shí)間過(guò)長(zhǎng),則會(huì)超時(shí)退出。

  1. 窗口1 
  2. mysql> update user set age = 20 where id =6; 
  3. ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 

 如果在窗口1中的事務(wù)在執(zhí)行寫操作等待期間,窗口2的事務(wù)也執(zhí)行同一行數(shù)據(jù)的寫操作,則會(huì)導(dǎo)致死鎖錯(cuò)誤。

  1. 窗口2 
  2. mysql> update user set age = 30 where id =6; 
  3. ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction 

 寫鎖

排他鎖(exclusive lock)也稱為寫鎖(write lock)。寫鎖是排他的,也就是一個(gè)寫鎖會(huì)阻塞其他的寫鎖和讀鎖。

加鎖命令

  1. select ...... for update

測(cè)試

  • 窗口1:查詢id=6的行數(shù)據(jù)并添加寫鎖,正確返回?cái)?shù)據(jù)。
  • 窗口2:依然查詢id=6的行數(shù)據(jù)并添加寫鎖,阻塞。寫寫沖突。
  • 窗口1:對(duì)id=6的行執(zhí)行寫操作(update語(yǔ)句),寫操作未阻塞。
  • 窗口1事務(wù)提交之后,窗口2的查詢語(yǔ)句返回結(jié)果。

悲觀鎖和樂(lè)觀鎖

不論是樂(lè)觀鎖還是悲觀鎖都是人們定義的一種概念,并不是一種鎖實(shí)現(xiàn),它是一種思想。樂(lè)觀鎖比較適用于讀多寫少的場(chǎng)景,悲觀鎖適用于寫多讀少的場(chǎng)景。

悲觀鎖

當(dāng)我們對(duì)數(shù)據(jù)庫(kù)的某一條數(shù)據(jù)進(jìn)行修改操作時(shí),為了避免同時(shí)有其他人對(duì)同一行數(shù)據(jù)進(jìn)行修改,通過(guò)對(duì)數(shù)據(jù)進(jìn)行加鎖的方式以防止并發(fā)問(wèn)題。這種借助了數(shù)據(jù)庫(kù)的鎖機(jī)制,在修改數(shù)據(jù)之前先鎖定再修改的方式稱為悲觀鎖(Pessimistic Lock)。

悲觀鎖具有強(qiáng)烈的獨(dú)占性和排他性,在整個(gè)數(shù)據(jù)的寫操作過(guò)程,都將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實(shí)現(xiàn)往往需要數(shù)據(jù)庫(kù)提供的鎖機(jī)制。

悲觀鎖的實(shí)現(xiàn):

  • 數(shù)據(jù)庫(kù)的鎖機(jī)制如行鎖、表鎖、讀鎖和寫鎖都是在操作之前先加鎖的操作,都屬于悲觀鎖。
  • Java中學(xué)習(xí)的synchronized關(guān)鍵字也是悲觀鎖。

樂(lè)觀鎖

樂(lè)觀鎖是相對(duì)于悲觀鎖的概念,樂(lè)觀鎖是假設(shè)數(shù)據(jù)一般情況下都不會(huì)存在并發(fā)沖突,在數(shù)據(jù)進(jìn)行更新的時(shí)候才會(huì)對(duì)數(shù)據(jù)的沖突與否進(jìn)行驗(yàn)證。如果存在沖突,則告訴用戶結(jié)果,由用戶決定下一步該怎么做。

樂(lè)觀鎖是一種寬松的加鎖方式,它不需要使用數(shù)據(jù)庫(kù)本身的鎖機(jī)制。

樂(lè)觀鎖的實(shí)現(xiàn):

  • MVCC,數(shù)據(jù)庫(kù)多版本控制利用版本號(hào)控制數(shù)據(jù)更新的并發(fā)問(wèn)題,是樂(lè)觀鎖的實(shí)現(xiàn)。
  • CAS,比較并交換是Java中樂(lè)觀鎖的實(shí)現(xiàn)。

全局鎖

全局鎖:對(duì)整個(gè)數(shù)據(jù)庫(kù)實(shí)例加鎖,它將整個(gè)數(shù)據(jù)庫(kù)實(shí)例處于只讀的狀態(tài)。

加鎖命令 (FTWRL)

  1. Flush tables with read lock; 

應(yīng)用場(chǎng)景

全局鎖常用來(lái)對(duì)整個(gè)數(shù)據(jù)庫(kù)實(shí)例進(jìn)行邏輯備份。

全局鎖加鎖期間,業(yè)務(wù)的數(shù)據(jù)更新操作(DML)和 表結(jié)構(gòu)的修改操作(DDL)都是會(huì)被鎖住的。

此時(shí)你是不是有個(gè)疑問(wèn):開發(fā)中備份都是直接使用mysqldump,什么時(shí)候使用FTWRL呢?

官方自帶的邏輯備份工具mysqldump 使用參數(shù)-single -transaction的時(shí)候,在導(dǎo)出數(shù)據(jù)的時(shí)候就會(huì)啟動(dòng)一個(gè)事務(wù),來(lái)確保拿到一致性視圖,在學(xué)習(xí)事務(wù)隔離的時(shí)候我們了解到,基于MVCC的一致性視圖,這個(gè)過(guò)程中的數(shù)據(jù)是可以正常更新的。但是我們要知道事務(wù)是引擎層的實(shí)現(xiàn),并不是每個(gè)存儲(chǔ)引擎都支持事務(wù)。我們?cè)陂_發(fā)中大部分的備份使用的是mysqldump,主要是因?yàn)槲覀兊拇鎯?chǔ)引擎大部分情況都是使用的默認(rèn)的引擎InnoDB。

表級(jí)鎖

表級(jí)鎖:即是對(duì)整張表進(jìn)行加鎖。表的定義包含兩個(gè)部分:數(shù)據(jù)和結(jié)構(gòu),所以表級(jí)鎖也分為兩類:表鎖和元空間鎖。

表鎖

表鎖是MySQL中最基本的鎖策略,并且也是開銷最小的策略。表鎖會(huì)鎖住整張表,在對(duì)表進(jìn)行寫操作(插入、刪除、更新等)前,需要先獲取寫鎖,它會(huì)阻塞其他用戶對(duì)該表的所有讀寫操作。只有沒(méi)有寫鎖時(shí),其他讀取的用戶才能獲取讀鎖。讀鎖之前互相不會(huì)造成阻塞。

寫鎖的優(yōu)先級(jí)高于讀鎖,因此一個(gè)寫鎖的請(qǐng)求可能會(huì)被插入到讀鎖隊(duì)列前面,但是讀鎖是不能插入到寫鎖的前面的。

加解鎖命令

  1. -- 對(duì)表加讀鎖 
  2. lock tables ...... read
  3. -- 對(duì)表加寫鎖 
  4. lock tables ...... write; 
  5. -- 釋放鎖 
  6. unlock tables; 

 測(cè)試

表鎖讀鎖測(cè)試

  • 窗口1:對(duì)user表加讀鎖。
  • 窗口2:對(duì)user表全表讀取,正常返回全表數(shù)據(jù)。
  • 窗口2:修改user表中id=6的數(shù)據(jù),阻塞。讀寫沖突。
  • 窗口1:修改user表中id=6的數(shù)據(jù),報(bào)錯(cuò)。
  • 窗口1:釋放讀鎖,窗口2的更新數(shù)據(jù)執(zhí)行成功。

表鎖寫鎖測(cè)試

  • 窗口1:對(duì)user表添加寫鎖。
  • 窗口2:全表查詢user表,阻塞。
  • 窗口1:更新user表中的id=6的數(shù)據(jù),更新成功。
  • 窗口1:釋放鎖,窗口2的全表查詢返回最新數(shù)據(jù)。

元空間鎖

MySQL5.5版本中引入了元空間鎖(matadata lock),當(dāng)對(duì)一個(gè)表做增刪改查操作的時(shí)候,會(huì)添加MDL讀鎖。當(dāng)對(duì)表結(jié)構(gòu)變更操作的時(shí)候,會(huì)添加MDL寫鎖。MDL的作用是防止DDL和DML并發(fā)的沖突。

MDL鎖是系統(tǒng)默認(rèn)添加的,不需要顯式的添加。

測(cè)試

  • 窗口1:查詢表中的一條數(shù)據(jù),這個(gè)時(shí)候在執(zhí)行查詢語(yǔ)句,會(huì)添加MDL讀鎖。
  • 窗口2:添加字段,此時(shí)執(zhí)行的是alter語(yǔ)句,會(huì)添加MDL寫鎖。這個(gè)時(shí)候窗口1的讀鎖沒(méi)有釋放,所以alter語(yǔ)句會(huì)阻塞。
  • 窗口3:查詢表中的一條數(shù)據(jù),由于窗口2導(dǎo)致的阻塞,在窗口3申請(qǐng)MDL讀鎖的時(shí)候也會(huì)造成阻塞。
  • 窗口1:提交事務(wù),窗口3獲取了MDL讀鎖,返回查詢結(jié)果。
  • 窗口3:提交事務(wù)釋放了讀鎖,窗口2獲取寫鎖,添加字段成功。

行級(jí)鎖

MySQL的行鎖是在引擎層由各個(gè)存儲(chǔ)引擎實(shí)現(xiàn)的。并不是所有的存儲(chǔ)引擎都支持行鎖,比如MyISAM引擎是不支持行鎖的。不支持行鎖意味著并發(fā)控制的時(shí)候只能使用表鎖,這也意味著同一個(gè)時(shí)刻同一個(gè)表只有一個(gè)更新執(zhí)行,嚴(yán)重影響了并發(fā)。InnoDB是支持行鎖的,這也是InnoDB能替代MyISM的重要原因之一。

兩階段鎖協(xié)議

在InnoDB事務(wù),行鎖是需要的時(shí)候加上的,但并不是不需要了就立刻釋放的,而是需要等到事務(wù)結(jié)束后才會(huì)釋放鎖。這個(gè)就是兩階段鎖協(xié)議。

InnoDB是采用的兩階段鎖協(xié)議。在事務(wù)執(zhí)行的過(guò)程中,隨時(shí)都可以鎖定,鎖只有在執(zhí)行commit或者rollback的時(shí)候才會(huì)釋放,并且所有的鎖是在同一個(gè)時(shí)刻釋放的。

事務(wù)A執(zhí)行了兩條update語(yǔ)句之后,事務(wù)B也執(zhí)行update語(yǔ)句,但是事務(wù)B阻塞直到事務(wù)A提交事務(wù)。

行鎖

我們創(chuàng)建一張簡(jiǎn)單表t,其中id為主鍵,a為索引,插入6條數(shù)據(jù)。

  1. CREATE TABLE `t1` ( 
  2.   `id` int(11) NOT NULL
  3.   `a` int(11) DEFAULT NULL
  4.   `b` int(11) DEFAULT NULL
  5.   PRIMARY KEY (`id`), 
  6.   KEY `idx` (`a`) 
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
  8. insert into t1 values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25); 

 間隙鎖(Gap Lock)

間隙鎖,鎖的是兩個(gè)值的間隙。

對(duì)于表t1,6條數(shù)據(jù)就產(chǎn)生了7個(gè)間隙,如下圖所示:

我們看前面學(xué)習(xí)的寫鎖的例子:

  1. begin; 
  2. select * from t1 where b = 5 for update
  3. commit
  • 加了寫鎖的select查詢是當(dāng)前讀,讀取的是最新的數(shù)據(jù)值。
  • b字段不是表的索引字段,它會(huì)掃描全表將滿足條件的行都加上寫鎖,也會(huì)給滿足條件的行兩邊的間隙加上了鎖。

間隙鎖之間并不會(huì)沖突,與間隙鎖存在沖突關(guān)系的是往這個(gè)間隙中插入數(shù)據(jù)的操作。

next-key lock

行鎖和間隙鎖的合稱為next-key lock每個(gè)next-key lock都是一個(gè)前開后閉的區(qū)間。這里不要混淆了,間隙鎖是一個(gè)開區(qū)間,間隙鎖加上行鎖生成的next-key lock是一個(gè)前開后閉的區(qū)間。

間隙鎖和next-key lock的引入幫助我們解決了幻讀的問(wèn)題。

間隙鎖是可重復(fù)隔離級(jí)別下才生效的,如果我們把隔離級(jí)別設(shè)置為讀提交,那就沒(méi)有間隙鎖了。

測(cè)試

前面我們?cè)趯W(xué)習(xí)其他鎖的時(shí)候,為了省事把a(bǔ)utocommit設(shè)置為了0,現(xiàn)在我們需要把a(bǔ)utocommit設(shè)置為1;

  • 窗口1:使用顯式事務(wù),通過(guò)for update加寫鎖,對(duì)滿足條件的行和間隙加鎖。
  • 窗口2:更新id為0的行,此行沒(méi)有加鎖更新成功。
  • 窗口3:插入數(shù)據(jù),滿足了(0,5]的next-key lock,阻塞等待。

總結(jié)

鎖按照鎖粒度分為:全局鎖、表鎖和行鎖。

行鎖是引擎層的實(shí)現(xiàn),我們文中描述的行鎖都是基于InnoDB存儲(chǔ)引擎的實(shí)現(xiàn)。

InnoDB的行鎖采用的兩階段鎖協(xié)議,鎖在需要的時(shí)候添加,只有在事務(wù)commit或者rollback時(shí)才會(huì)一次性釋放所有鎖。

可重復(fù)度隔離級(jí)別下存在間隙鎖,如果設(shè)置為其他的隔離級(jí)別下就沒(méi)有間隙鎖了。間隙鎖即是對(duì)行數(shù)據(jù)的兩邊間隙進(jìn)行加鎖,間隙鎖加上行鎖合稱為next-key lock,它是一個(gè)前開后閉的區(qū)間。間隙鎖解決了幻讀的問(wèn)題。

大家在學(xué)習(xí)鎖的時(shí)候還需多動(dòng)手實(shí)踐。

 

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2021-03-12 09:21:31

MySQL數(shù)據(jù)庫(kù)邏輯架構(gòu)

2021-04-30 09:04:11

Go 語(yǔ)言結(jié)構(gòu)體type

2021-07-12 06:11:14

SkyWalking 儀表板UI篇

2021-03-18 08:53:44

MySQL數(shù)據(jù)庫(kù)索引

2022-03-03 09:05:17

索引MySQL數(shù)據(jù)查詢

2021-05-19 08:12:39

etcd分布式鎖分布式系統(tǒng)

2021-10-28 08:51:53

GPIO軟件框架 Linux

2021-04-14 07:55:45

Swift 協(xié)議Protocol

2022-02-25 15:50:05

OpenHarmonToggle組件鴻蒙

2023-03-13 09:31:04

2021-07-08 07:30:13

Webpack 前端Tree shakin

2021-05-08 08:36:40

ObjectString前端

2021-04-23 08:59:35

ClickHouse集群搭建數(shù)據(jù)庫(kù)

2021-06-21 14:36:46

Vite 前端工程化工具

2021-01-28 08:55:48

Elasticsear數(shù)據(jù)庫(kù)數(shù)據(jù)存儲(chǔ)

2023-03-29 07:45:58

VS編輯區(qū)編程工具

2021-04-14 14:16:58

HttpHttp協(xié)議網(wǎng)絡(luò)協(xié)議

2021-04-08 11:00:56

CountDownLaJava進(jìn)階開發(fā)

2024-06-13 08:34:48

2022-03-22 09:09:17

HookReact前端
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 精品国产乱码久久久久久闺蜜 | 性国产xxxx乳高跟 | 91人人爽 | 欧美日韩淫片 | 国产美女自拍视频 | 国产欧美一区二区三区国产幕精品 | 成年视频在线观看福利资源 | 日韩在线精品视频 | 国产乱码精品一区二区三区五月婷 | 国产在线精品一区二区三区 | 国产成人精品一区二区三区四区 | 91精品国产乱码久久久久久久久 | 91精品入口蜜桃 | 亚洲 中文 欧美 日韩 在线观看 | 在线伊人网 | 日韩欧美中文字幕在线观看 | 国产在线精品一区二区 | 久久夜视频| 国产精品波多野结衣 | 久久久久久久久久性 | 91高清在线| 在线看av的网址 | 日一区二区 | 91在线一区二区三区 | 久久久精品视频免费 | 亚洲久久| 久久久久久久av | 一起操网站 | 成人欧美一区二区三区在线观看 | 亚洲视频在线看 | 亚洲精品在| 亚洲精品视频在线看 | 久久成人一区 | 日韩免费视频一区二区 | 欧美视频一区二区三区 | 国产乱码精品一区二区三区中文 | 国产精品乱码一区二区三区 | 欧美激情在线一区二区三区 | 99久久久久久久 | 国产高清免费视频 | wwwww在线观看 |