hymn

忽有故人心头过,回首山河已是秋。

  menu
132 文章
0 浏览
2 当前访客
ღゝ◡╹)ノ❤️

MySQL死锁

以下,均参考自58沈剑公众号

innodb_locks_unsafe_for_binlog
	NO  表示关闭区间锁,此时一致性会被破坏,所以是unsafe
	OFF 表示开启区间锁
	查询区间锁是否关闭:select global variables like "innodb_lock%";
MySQL 默认把每一条sql当做一个事务,自动提交
	查询是否关闭自动提交:select globle variables like "autocommit";
	任何连接MySQL 的 session 都要手动提交: set session autocommit=0;
	修改session变量,并不影响global变量,全局其他的session仍然是ON。
	session变量默认继承global变量,也可以单独修改
查询MySQL 隔离级别
	select globle variables like "tx_isolation"

设置隔离级别
	set session trancation isolation level X
	X 可以等于
	read uncommitted
	read committed
	repeatable read 
	serilizable
事务A删除某个区间内的一条不存在记录,获取到共享间隙锁,
会阻止其他事务B在相应的区间插入数据,因为插入需要获取排他间隙锁
共享排他锁死锁
MySQL insert,update,delete执行时,会先回去共享锁(共享记录锁或者共享间隙锁),
检验PK是否冲突或者间隙内数据是否存在。然后获获取排它锁(排他记录锁或者怕他间隙锁)。
	例子:MySQL设置手动提交,关闭自动提交
		三个session(ABC)同时插入一条id=7的数据
		A 先执行,获得id=7的排他锁
		B 后执行,获得id=7的共享锁,检验Pk是否冲突
		C 后执行,获得id=7的共享锁,检验Pk是否冲突
		这是A 执行rollback;释放排他锁

		BC还在共享锁,Pk不冲突,都想获取排它锁,但是他们获取了共享锁,无法获取彼此的排它锁,
		假设B获取到排它锁,但是C获得了共享锁,一直不提交,不释放锁,B是不可能获得排他锁的,
		所以矛盾,只有在事务提交后,都释放了共享锁,才会获得排它锁,所以产生了死锁。
并发间隙锁的死锁
A:set session autocommit=0;
A:start transaction;
A:delete from t where id=6;
         B:set session autocommit=0;
         B:start transaction;
         B:delete from t where id=7;
A:insert into t values(5);
         B:insert into t values(8);
 
A执行delete后,会获得(3, 10)的共享间隙锁。
B执行delete后,也会获得(3, 10)的共享间隙锁。
A执行insert后,希望获得(3, 10)的排他间隙锁,于是会阻塞。
B执行insert后,也希望获得(3, 10)的排他间隙锁,于是死锁出现。

并发事务,间隙锁可能互斥
(1)A删除不存在的记录,获取共享间隙锁;
(2)B插入,必须获得排他间隙锁,故互斥;
并发插入相同记录,可能死锁(某一个回滚)
并发插入,可能出现间隙锁死锁(难排查)

show engine innodb status; 可以查看InnoDB的锁情况,也可以调试死锁
总结:产生死锁的原因,两个线程同时获取到同一个条件,但是同时需要另外一个释放条件才能执行,这时会产生死锁。
java栗子:
	1、sync(a){sync(b)}
	2、sync(b){sync(a)}
	AB线程同时进入1、2方法,A线程锁住a,B锁住b,A要执行sync(b),必须等待B线程释放b,
	B要执行sync(a),必须等待A释放sync(a),所以,出现死锁

标题:MySQL死锁
作者:hymn
地址:https://dxyhymn.com/articles/2020/06/24/1592993474117.html