MySQL锁问题

锁机制出现的背景

  • 最大限度的利用数据库的并发访问
  • 每个用户以一致的方式读取和修改数据

什么是锁

用于管理对共享资源的并发访问,从而保证数据的完整性和一致性

InnoDB存储引擎中的锁

  • 共享锁:允许读一行数据
  • 排他锁:允许更新或者删除一行数据

只有同时是共享锁的时候兼容,其他组合均互斥。

InnoDB 支持多粒度的锁,这种锁允许事务在行级锁和表级锁同时存在。

为支持在不同粒度上进行加锁操作,InnoDB存储引擎支持一种额外的锁方式,称之为意向锁(Intention Lock)

  • 意向共享锁(IS Lock): 事务想要获得一张表中某几行的共享锁
  • 意向排他锁(IX Lock): 事务想要获得一张表中某几行的排他锁

IS、IX锁是表级锁,它们的提出仅仅为了在之后加表级别的S锁和X锁时可以快速判断表中的记录是否被上锁,以避免用遍历的方式来查看表中有没有上锁的记录,也就是说其实IS锁和IX锁是兼容的,IX锁和IX锁是兼容的,本质上只是一种标记。

一致性非锁定读

事务利用MVCC进行的读取操作称之为一致性读,或者一致性无锁读,有的地方也称之为快照读。
所有普通的SELECT语句(plain SELECT)在READ COMMITTED、REPEATABLE READ隔离级别下都算是一致性读。
如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此去等待行上锁的释放

详细内容参见MySQL事务隔离级别详解及MVCC实现原理

一致性锁定读

InnoDB存储引擎的SELECT操作使用一致性非锁定读,但在某些情况下,用户需要显式地对数据库读取操作进行加锁以保证数据逻辑的一致性。
锁定读的语句:

//对读取记录加一个S锁,其他事务只能加S锁,不能加X锁
SELECT ... LOCK IN SHARE MODE;
//对读取记录加一个X锁,其他事务不能对已锁定的行加任何锁
SELECT ... FOR UPDATE;

常见写操作

  • DELETE:定位待删除记录在B+树中位置的过程看成是一个获取X锁的锁定读。
  • UPDATE:键值、空间不变,X锁,键值不变,空间变,首先定位为X锁,插入用隐式锁,键值变,相当于删除,后插入
  • INSERT:新插入一条记录的操作并不加锁,通过隐式锁来保护这条新插入的记录在本事务提交前不被别的事务访问

锁的算法

Mysql全局锁、表锁、行锁

三种行锁的算法

  • Record Lock:单个行记录上的锁,总是会锁定索引
  • Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
  • Next-Key Lock∶Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身

例如一个索引有10,11,13和20这四个值,那么该索引可能被Next-Key Locking的区间为:(负无穷,10],(10,11] ,(11,13],(13,20],(20,正无穷)

当查询的索引是唯一属性的时候,InnoDB存储引擎会对Next-Key Lock优化,将其降级为Record Lock。

解决幻读问题

MySQL InnoDB的可重复读并不保证避免幻读,需要应用使用加锁读来保证,在可重复度隔离级别下,且禁用innodb_locks_unsafe_for_binlog的情况下,InnoDB存储引擎采用Next-Key Locking机制来避免幻读问题。

阻塞

因为不同锁之间的兼容性关系,在有些时刻一个事务中的锁需要等待另一个事务中的锁释放它所占用的资源,这就是阻塞。阻塞并不是一件坏事,其是为了确保事务可以并发且正常地运行。

死锁

两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。

解决死锁问题

超时

等待图

注意:

  • read uncommitted 读不加锁,写加排他锁,并到事务结束之后释放。

你可能感兴趣的:(每天一道面试题,MySQL)