




SESSION 2 delete from delete_test where name = '33' and id < 6;


结果还是一样的,还是死锁了从结果看,我们锁在 5
为什么因为删除会导致锁扩大,我们将操作变化为UPDATE 的操作看看结果如何



答案很明显,同样的语句更换为UPDATE 后,数据将不会在产生死锁,从此我们可以得出一个结论,DELETE 与UPDATE 操作同样的数据,最终的结果是DELETE 会产生死锁,UPDATE 不会。
为什么会这样,我已经使用了RC ,而不是RR, 为什么还会导致这样的问题,首先即使是RC ,在每个数据库的操作中都会产生SNAPSHOT,而在这个事务的生命周期中,在进行插入和删除要满足一个条件,就是在一个事务的操作的记录范围内,与另一个事务的操作的范围内,不能有重合,这里不是指的实际的范围,而是你条件的范围。这里MYSQL的设计中的思想是,对所有有可能产生变化的记录全部要加锁,包含不存在的KEY,一般来说如果设计中通过条件来判断操作的范围即可,如我们上面的操作中,一个只要锁3,4 记录即可,另一个只要锁 5好记录即可,但是这使我们人类的想法,而到了数据库中,条件的范围是需要判断的,而且COST 很大,你不知道一个条件的COST 是大是小,所以基于MYSQL的B+TREE 的方式中,无论你DELETE 的操作使用什么隔离级别(RN除外),你都会导致一个key range locking 的锁,保护你操作的区间的记录不被 INSERT 或 DELETE 操作后变化产生的不可预知的数据逻辑错误的问题。
所以我们上面的操作是告知开发一个在使用MYSQL 中重要的问题,不要对数据库进行DELETE操作,这里指的是你的应用程序。应用程序将DELETE 操作更换为,UPDATE 的操作,因为UPDATE 的操作本身并不会引起记录的缺少或增多。这里我们不谈你更新主键的问题,因为从业务或数据库的角度来说,我们都不建议你一个开发去更新主键,这在MYSQL中是一个最大的忌讳。
当然如果想监控到特别详细的锁信息,如果你在show egine innodb status; 中没有发现记录,那么是你下面的这两个部分没有开。
SET GLOBAL innodb_status_output=ON;
SET GLOBAL innodb_status_output_locks=ON;

