亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MySQL產(chǎn)生死鎖原因分析講解

 更新時(shí)間:2022年12月16日 14:52:49   作者:知其黑、受其白  
死鎖指的是在兩個(gè)或兩個(gè)以上不同的進(jìn)程或線程中,由于存在共同資源的競(jìng)爭(zhēng)或進(jìn)程(或線程)間的通訊而導(dǎo)致各個(gè)線程間相互掛起等待,如果沒(méi)有外力作用,最終會(huì)引發(fā)整個(gè)系統(tǒng)崩潰

鎖類型介紹

MySQL 有三種鎖的級(jí)別:頁(yè)級(jí)、表級(jí)、行級(jí)

1 表級(jí)鎖:開(kāi)銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高, 并發(fā)度最低。

2 行級(jí)鎖:開(kāi)銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低, 并發(fā)度也最高。

3 頁(yè)面鎖:開(kāi)銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。

死鎖產(chǎn)生原因和示例

1、產(chǎn)生原因

所謂死鎖 <DeadLock>:是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過(guò)程中, 因爭(zhēng)奪資源而造成的一種互相等待的現(xiàn)象, 若無(wú)外力作用,它們都將無(wú)法推進(jìn)下去. 此時(shí)稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱為死鎖進(jìn)程。表級(jí)鎖不會(huì)產(chǎn)生死鎖. 所以解決死鎖主要還是針對(duì)于最常用的 InnoDB。

死鎖的關(guān)鍵在于:兩個(gè) (或以上) 的 Session 加鎖的順序不一致。

那么對(duì)應(yīng)的解決死鎖問(wèn)題的關(guān)鍵就是:讓不同的 session 加鎖有次序。

2、產(chǎn)生示例

案例一

需求:將投資的錢拆成幾份隨機(jī)分配給借款人。

起初業(yè)務(wù)程序思路是這樣的:

投資人投資后,將金額隨機(jī)分為幾份,然后隨機(jī)從借款人表里面選幾個(gè),然后通過(guò)一條條 select for update 去更新借款人表里面的余額等。

例如兩個(gè)用戶同時(shí)投資:

A 用戶金額隨機(jī)分為 2 份,分給借款人 1,2

B 用戶金額隨機(jī)分為 2 份,分給借款人 2,1

由于加鎖的順序不一樣,死鎖當(dāng)然很快就出現(xiàn)了。

對(duì)于這個(gè)問(wèn)題的改進(jìn)很簡(jiǎn)單,直接把所有分配到的借款人直接一次鎖住就行了。

Select * from xxx where id in (xx,xx,xx) for update

在 in 里面的列表值 mysql 是會(huì)自動(dòng)從小到大排序,加鎖也是一條條從小到大加的鎖例如(以下會(huì)話 id 為主鍵):

Session1:

mysql> select * from t3 where id in (8,9) for update;
+----+--------+------+---------------------+
| id | course | name | ctime               |
+----+--------+------+---------------------+
|  8 | WA     | f    | 2016-03-02 11:36:30 |
|  9 | JX     | f    | 2016-03-01 11:36:30 |
+----+--------+------+---------------------+
rows in set (0.04 sec)

Session2:

select * from t3 where id in (10,8,5) for update;

鎖等待中……

其實(shí)這個(gè)時(shí)候 id=10 這條記錄沒(méi)有被鎖住的,但 id=5 的記錄已經(jīng)被鎖住了,鎖的等待在 id=8 的這里 不信請(qǐng)看。

Session3:

mysql> select * from t3 where id=5 for update;

鎖等待中

Session4:

mysql> select * from t3 where id=10 for update;
+----+--------+------+---------------------+
| id | course | name | ctime               |
+----+--------+------+---------------------+
| 10 | JB     | g    | 2016-03-10 11:45:05 |
+----+--------+------+---------------------+
row in set (0.00 sec)

在其它 session 中 id=5 是加不了鎖的,但是 id=10 是可以加上鎖的。

案例二

在開(kāi)發(fā)中,經(jīng)常會(huì)做這類的判斷需求:根據(jù)字段值查詢(有索引),如果不存在,則插入;否則更新。

以 id 為主鍵為例,目前還沒(méi)有 id=22 的行

Session1:

select * from t3 where id=22 for update;
Empty set (0.00 sec)

session2:

select * from t3 where id=23  for update;
Empty set (0.00 sec)

Session1:

insert into t3 values(22,'ac','a',now());

鎖等待中……

Session2:

insert into t3 values(23,'bc','b',now());

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

當(dāng)對(duì)存在的行進(jìn)行鎖的時(shí)候 (主鍵),mysql 就只有行鎖。

當(dāng)對(duì)未存在的行進(jìn)行鎖的時(shí)候 (即使條件為主鍵),mysql 是會(huì)鎖住一段范圍(有 gap 鎖)

鎖住的范圍為:

(無(wú)窮小或小于表中鎖住 id 的最大值,無(wú)窮大或大于表中鎖住 id 的最小值)

如:如果表中目前有已有的 id 為(11 , 12),那么就鎖?。?2,無(wú)窮大)

如果表中目前已有的 id 為(11 , 30),那么就鎖?。?1,30)

對(duì)于這種死鎖的解決辦法是:

insert into t3(xx,xx) on duplicate key update `xx`='XX';

用 mysql 特有的語(yǔ)法來(lái)解決此問(wèn)題。

因?yàn)?insert 語(yǔ)句對(duì)于主鍵來(lái)說(shuō),插入的行不管有沒(méi)有存在,都會(huì)只有行鎖。

案例三

mysql> select * from t3 where id=9 for update;
+----+--------+------+---------------------+
| id | course | name | ctime               |
+----+--------+------+---------------------+
|  9 | JX     | f    | 2016-03-01 11:36:30 |
+----+--------+------+---------------------+
row in set (0.00 sec)

Session2:

mysql> select * from t3 where id<20 for update;

鎖等待中…

Session1:

mysql> insert into t3 values(7,'ae','a',now());

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

這個(gè)跟案例一其它是差不多的情況,只是 session1 不按常理出牌了。

Session2 在等待 Session1 的 id=9 的鎖,session2 又持了 1 到 8 的鎖(注意 9 到 19 的范圍并沒(méi)有被 session2 鎖住),最后,session1 在插入新行時(shí)又得等待 session2, 故死鎖發(fā)生了。

這種一般是在業(yè)務(wù)需求中基本不會(huì)出現(xiàn),因?yàn)槟沔i住了 id=9,卻又想插入 id=7 的行,這就有點(diǎn)跳了,當(dāng)然肯定也有解決的方法,那就是重理業(yè)務(wù)需求,避免這樣的寫法。

案例四

一般的情況,兩個(gè) session 分別通過(guò)一個(gè) sql 持有一把鎖,然后互相訪問(wèn)對(duì)方加鎖的數(shù)據(jù)產(chǎn)生死鎖。

案例五

兩個(gè)單條的 sql 語(yǔ)句涉及到的加鎖數(shù)據(jù)相同,但是加鎖順序不同,導(dǎo)致了死鎖。

案例六

CREATE TABLE dltask (
    id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
    a varchar(30) NOT NULL COMMENT 'uniq.a',
    b varchar(30) NOT NULL COMMENT 'uniq.b',
    c varchar(30) NOT NULL COMMENT 'uniq.c',
    x varchar(30) NOT NULL COMMENT 'data',   
    PRIMARY KEY (id),
    UNIQUE KEY uniq_a_b_c (a, b, c)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='deadlock test';

a,b,c 三列,組合成一個(gè)唯一索引,主鍵索引為 id 列。

事務(wù)隔離級(jí)別:RR (Repeatable Read)

每個(gè)事務(wù)只有一條 SQL:

delete from dltask where a=? and b=? and c=?;

到此這篇關(guān)于MySQL產(chǎn)生死鎖原因分析講解的文章就介紹到這了,更多相關(guān)MySQL死鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論