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),所以,出现死锁