以下,均参考自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),所以,出现死锁