Database-Mysql-事务的隔离级别与死锁案例

Database-Mysql-事务的隔离级别与死锁案例

  • Mysql 的隔离级别:
    • 全局修改
    • 当前session修改
  • 死锁
    • 插入导致的死锁--GAP锁和Next-Key锁

Mysql 的隔离级别:

1)read uncommitted : 读未提交。读取尚未提交的数据 :就是脏读
2)read committed:读已提交。读取已经提交的数据 :可以解决脏读
3)repeatable read:可重复读。重读读取:可以解决脏读 和 不可重复读 —mysql默认的隔离级别
4)serializable:串行化:可以解决 脏读 不可重复读 和 虚读—相当于锁表

修改事务隔离级别的方法:

全局修改

修改mysql.ini配置文件,在最后加上
1 #可选参数有:READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE.
2 [mysqld]
3 transaction-isolation = REPEATABLE-READ

这里全局默认是REPEATABLE-READ,其实MySQL本来默认也是这个级别。(oracle支持第二个和第四个,默认工作在第二个级别)

当前session修改

在登录mysql客户端后,执行命令:
set session transaction isolation level read uncommitted;

死锁

Mysql中产生死锁的原因有很多:隔离级别、索引顺序、GAP锁、业务逻辑等。

插入导致的死锁–GAP锁和Next-Key锁

在InnoDB存储引擎里,可重复读(repeatable read)隔离级别中有一个锁叫做GAP锁。这个锁是为了保证插入时不会产生幻读。

1、行锁
锁定的是索引记录,而不是行数据,也就是说锁定的是key。

2、GAP锁
又叫间隙锁,说的简单些,GAP就是在索引树中插入新记录的空隙。GAP锁就是锁定索引记录的间隙,确保索引记录的间隙不变。
关于GAP锁还可参考 http://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html。

3、Next-Key锁
行锁和间隙锁组合起来就叫Next-Key Lock。
Next-Key Lock是行锁和间隙锁的组合,当InnoDB扫描索引记录的时候,会首先对索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。加上间隙锁之后,其他事务就不能在这个间隙修改或者插入记录。

我们假设这样一种情况(Innodb下的REPEATABLE-READ模式),在一个定义了主键和唯一索引的表中:
1、事务1插入一条记录(3,8)
2、事务2插入一条记录(5,8)
3、事务1插入一条记录(6,7)

在这里第二步事务2插入的记录(5,8)由于唯一索引的存在会检查其唯一性,事务2检查到此时还活跃着的事务1插入的记录(3,8)冲突,这时事务2会给该记录加上写锁,事务2会被阻塞而处于waiting状态。
紧接着第三步事务1插入(6,7)时,系统首先会找一个逻辑上合适的位置,注意此时页面位置逻辑上是排序的,因此(6,7)需要插入到(3,8)前面,但是Next-Key锁检测到已经有锁,这时就会出现环和死锁。

具体的加锁情况可以使用show engine innodb status来显示。
在这种情况下,第三步等待第二步,第二步等待第一步,而第一步和第三步的锁属于同一事务,这时系统会将事务2杀掉(回滚)。

这个例子中出现死锁问题最主要的原因是出现了对唯一索引的唯一性检查最终导致死锁的出现。另外在repeatable read级别下,为了防止幻读又使用了GAP锁进行插入操作,这就导致了锁粒度增大死锁频繁。

因此,如果业务无特殊需求,建议将隔离级别设置为read committed,这样会避免很多问题。

你可能感兴趣的:(Database,mysql,死锁,隔离级别)