mysql死锁的例子_GitHub - yxp199249/mysql-deadlocks: 收集一些常见的 MySQL 死锁案例
mysql-deadlocks
在工作過(guò)程中偶爾會(huì)遇到死鎖問(wèn)題,雖然這種問(wèn)題遇到的概率不大,但每次遇到的時(shí)候要想徹底弄懂其原理并找到解決方案卻并不容易。這個(gè)項(xiàng)目收集了一些常見(jiàn)的 MySQL 死鎖案例,大多數(shù)案例都來(lái)源于網(wǎng)絡(luò),并對(duì)其進(jìn)行分類匯總,試圖通過(guò)死鎖日志分析出每種死鎖的原因,還原出死鎖現(xiàn)場(chǎng)。
實(shí)際上,我們?cè)诙ㄎ凰梨i問(wèn)題時(shí),不僅應(yīng)該對(duì)死鎖日志進(jìn)行分析,還應(yīng)該結(jié)合具體的業(yè)務(wù)代碼,或者根據(jù) binlog,理出每個(gè)事務(wù)執(zhí)行的 SQL 語(yǔ)句。
我將這些死鎖按事務(wù)執(zhí)行的語(yǔ)句和正在等待或已持有的鎖進(jìn)行分類匯總:
事務(wù)一語(yǔ)句
事務(wù)二語(yǔ)句
事務(wù)一等待鎖
事務(wù)二等待鎖
事務(wù)二持有鎖
案例
insert
insert
lock_mode X insert intention
lock_mode X insert intention
lock_mode X
insert
insert
lock_mode X locks gap before rec insert intention
lock_mode X locks gap before rec insert intention
lock_mode X locks gap before rec
insert
insert
lock_mode X insert intention
lock_mode X insert intention
lock_mode S
insert
insert
lock mode S
lock_mode X locks gap before rec insert intention
lock_mode X locks rec but not gap
delete
insert
lock_mode X locks rec but not gap
lock mode S
lock_mode X locks rec but not gap
delete
delete
lock_mode X
lock mode S
lock_mode X locks rec but not gap
delete
delete
lock_mode X
lock mode X
lock_mode X locks rec but not gap
delete
delete
lock_mode X locks rec but not gap
lock_mode X
lock_mode X
delete
delete
lock_mode X locks rec but not gap
lock mode X
lock_mode X locks rec but not gap
delete
delete
lock_mode X locks rec but not gap
lock_mode X locks rec but not gap
lock_mode X locks rec but not gap
delete
insert
lock_mode X
lock_mode X locks gap before rec insert intention
lock_mode X locks rec but not gap
delete
insert
lock_mode X
lock_mode X locks gap before rec insert intention
lock_mode S
delete
insert
lock_mode X
lock_mode X locks gap before rec insert intention
lock_mode X
delete
insert
lock_mode X
lock mode S
lock_mode X locks rec but not gap
update
update
lock_mode X locks rec but not gap
lock mode S
lock_mode X locks rec but not gap
update
update
lock_mode X
lock_mode X locks gap before rec insert intention
lock_mode X locks rec but not gap
update
update
lock_mode X locks gap before rec insert intention
lock_mode X locks gap before rec insert intention
lock_mode X
update
delete
lock_mode X locks rec but not gap
lock_mode X
lock mode S
update
update
lock_mode X locks rec but not gap waiting
lock_mode X locks rec but not gap waiting
lock_mode X locks rec but not gap
表中的語(yǔ)句雖然大多數(shù)只列出了 delete 和 insert,但實(shí)際上絕大多數(shù)的 delete 語(yǔ)句和 update 或 select ... for update 加鎖機(jī)制是一樣的,所以為了避免重復(fù),對(duì)于 update 語(yǔ)句就不在一起匯總了(當(dāng)然也有例外,譬如使用 update 對(duì)索引進(jìn)行更新時(shí)加鎖機(jī)制和 delete 是有區(qū)別的,這種情況我會(huì)單獨(dú)列出,如案例 11)。
對(duì)每一個(gè)死鎖場(chǎng)景,我都會(huì)定義一個(gè)死鎖名稱(實(shí)際上就是事務(wù)等待和持有的鎖),每一篇分析,我都分成了 死鎖特征、死鎖日志、表結(jié)構(gòu)、重現(xiàn)步驟、分析和參考 這幾個(gè)部分。
對(duì)于這種分類方法我感覺(jué)并不是很好,但也想不出什么其他更好的方案,如果你有更好的建議,歡迎討論。另外,如果你有新的死鎖案例,或者對(duì)某個(gè)死鎖的解釋有異議,歡迎給我提 Issue 或 PR。
死鎖分析
之前寫過(guò)關(guān)于死鎖的一系列博客,供參考。
死鎖重現(xiàn)
docker 目錄下包含了各個(gè)死鎖重現(xiàn)的測(cè)試腳本,測(cè)試步驟如下:
創(chuàng)建數(shù)據(jù)庫(kù)和初始數(shù)據(jù)
# cd docker
# docker-compose up -d
確保機(jī)器上安裝了 docker 和 docker-compose,上面的命令會(huì)啟動(dòng)一個(gè) mysql:5.7 的容器,并創(chuàng)建一個(gè)名為 dldb 的數(shù)據(jù)庫(kù),初始密碼為 123456,并通過(guò) docker-entrypoint-initdb.d 初始化所有案例所需要的表和數(shù)據(jù)。
等待容器啟動(dòng)結(jié)束
# docker logs -f dldb
使用 dockere logs 查看容器啟動(dòng)日志,如果出現(xiàn)數(shù)據(jù)初始化完成的提示,如下所示,則進(jìn)入下一步。
MySQL init process in progress...
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/t16.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/t18.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/t8.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
MySQL init process done. Ready for start up.
進(jìn)入容器執(zhí)行測(cè)試腳本
首先進(jìn)入容器:
# docker exec -it dldb bash
然后執(zhí)行測(cè)試腳本,測(cè)試腳本在每一個(gè)案例對(duì)應(yīng)的 SQL 文件中,比如案例 18 對(duì)應(yīng)的測(cè)試腳本如下:
# mysqlslap --create-schema dldb -q "begin; delete from t18 where id = 4; insert into t18 (id) values (4); rollback;" --number-of-queries=100000 -uroot -p123456 &
# mysqlslap --create-schema dldb -q "begin; delete from t18 where id = 4; rollback;" --number-of-queries=100000 -uroot -p123456 &
測(cè)試腳本通過(guò) mysqlslap 工具并發(fā)執(zhí)行兩個(gè)事務(wù),每個(gè)事務(wù)執(zhí)行 N 次(N = 100000),如果兩個(gè)事務(wù)會(huì)出現(xiàn)死鎖,則我們可以通過(guò)死鎖日志看到。
檢查是否出現(xiàn)死鎖日志
# tail -f /var/log/mysql/error.log
TODO
重現(xiàn)案例 1
重現(xiàn)案例 2
重現(xiàn)案例 3
重現(xiàn)案例 4
重現(xiàn)案例 5
重現(xiàn)案例 6
重現(xiàn)案例 7
重現(xiàn)案例 8
重現(xiàn)案例 9
重現(xiàn)案例 10
重現(xiàn)案例 11
重現(xiàn)案例 12
重現(xiàn)案例 13
重現(xiàn)案例 14
重現(xiàn)案例 15
重現(xiàn)案例 16
重現(xiàn)案例 17
重現(xiàn)案例 18
重現(xiàn)案例 19
重現(xiàn)案例 20
由于相同的測(cè)試腳本在并發(fā)的時(shí)候可能產(chǎn)生不同的死鎖,后續(xù)可以寫個(gè)腳本來(lái)解析 error.log 看看發(fā)生了多少次死鎖
使用 mysqlslap 測(cè)試不太方面,后續(xù)可以寫個(gè)腳本來(lái)模擬并發(fā)事務(wù)
總結(jié)
以上是生活随笔為你收集整理的mysql死锁的例子_GitHub - yxp199249/mysql-deadlocks: 收集一些常见的 MySQL 死锁案例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: NB物联网之天翼物联(3)——初窥编解码
- 下一篇: Oracle数据库语句大全