MySQL會發生死鎖嗎?

Real_man發表於2019-03-25

MySQL的InnoDB引擎事務有4種隔離級別,主要是為了保證資料的一致性。

InnoDB引擎提供了行級鎖,表鎖。MyISAM提供了表鎖,如題,MySQL會發生死鎖嗎?

會,在InnoDB引擎下,RR(REPEATABLE-READ)級別,如果多個事務爭搶同一個資源,會發生死鎖。在RR級別下,MySQL提供了next-key lock。假如一個索引的行有10,11,13,20 那麼可能的next-key lock的包括: (無窮小, 10] (10,11] (11,13] (13,20] (20, 無窮大)

即:當你查詢12時,如果資料未查到,那麼將對(12,13]範圍內的資料進行鎖定。next-key lock的定義可以到官方具體檢視,這裡做個演示。

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(200) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1111 DEFAULT CHARSET=utf8;
複製程式碼

image-20190304142624761

//檢視隔離級別,
show variables like '%tx_isolation%';
// 設定隔離界別
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
// 不設定自動提交
SET autocommit = 0;
複製程式碼

死鎖演示

  1. 首先將隔離級別都設定為RR級別的,並且不讓事務自動提交
  2. 根據上面的資料,在事務1中查詢
// 得到空結果集,此時鎖定的範圍是(33,100]
select * FROM user where id=33 for update;
複製程式碼
  1. 在事務2中也進行查詢
// 查詢到空的結果,在事務2中鎖定的範圍是(34,100]
select * FROM user where id=34 for update
複製程式碼
  1. 在事務1中插入資料
// 雖然事務1鎖定了範圍,事務2也鎖定了範圍
insert into user values(35,'ac',10);
複製程式碼

image-20190304143355381

  1. 在事務2中也插入資料
insert into user values(34,'ac',10)
複製程式碼

image-20190304143707234

  1. 可以發現已經發生了死鎖

解決辦法

  1. 設定死鎖的超時時長

innodb_lock_wait_timeout=500

  1. 查詢到當前正在鎖定的事務執行緒,將其殺死
// 可以看到正在執行的事務執行緒,還有執行狀態
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

//trx_mysql_thread_id為上一條命令獲取的結果,將具體的數字替換一下即可。
kill trx_mysql_thread_id
複製程式碼

最後

就演示到這了

相關文章