MySQL 锁

一、什么是锁

  • 锁是数据库系统区别于文件系统的一个关键特性,锁机制用于管理对共享资源的并发访问。InnoDB存储引擎会在行级别上对表数据加锁。MyIsAM引擎锁是表锁设计,并发情况下的读没有问题,但是并发的插入性能就要差一些。

页锁、表锁、行锁,锁是一种稀有的资源锁越多开销就越大,因此会有锁升级,在这种情况下,行锁会升级到表锁。

1、Lock 与 Latch

数据库中Lock 与 Latch都可以称之为锁,胆二者截然不同。


  1. Latch 一般称之为 闩锁也就是轻量级的锁,因为其要求锁定的时间必须非常短。若持续的时间长则性能非常差。
    • InnoDB存储引擎中Latch 又分为mutex【互斥量】、rwLock【读写锁】,—目的是用来保证线程并发操作临界资源的正确性并且通常没有死锁检测的机制。
  1. Lock的对象是事务:用来锁定的是数据库中的对象,如:表、页、行、并且Lock的对象一般仅在commit 和rollback后进行释放【不同事务隔离级别释放的时间可能不同】。此外Lock具有死锁机制。

locklatch
对象事务线程
保护数据库内容内存数据结构
持续时间整个事务过程临界资源
模式行锁、表锁、意向锁读写锁、互斥量
死锁通过wait-for、graph、time out等机制进行死锁检测与处理无死锁检测与处理机制。仅通过应用程序加锁的顺序【保证无死锁的情况发生】
存在于LockManager的哈希表中每个数据结构的对象中
2、InnoDB存储引擎中的锁
  • InnoDB存储引擎中实现了如下两种标准的行级锁【行级别】:

1.共享锁【S Lock】 允许事务读一行数据。
2.排它锁【X Lock】 允许事务删除或更新一行数据。

  • 如果一个事务T1 已经获得了行R的共享锁,那么另外的事务T2 可以立即获得行R的共享锁,因为读取并没有改变行R的数据【这种情况被称为锁兼容】.但是若有其他的事务T3想获得行R的排他锁 ,则必须等待事务T1、T2 释放行R上的共享锁【这种情况称为锁不兼容】。
  • 排它锁和共享锁的兼容性

XS
X不兼容不兼容
S不兼容兼容

从上面我们发现X锁和任何锁都不兼容,而S锁仅和S锁兼容。S锁和X锁都是行锁,兼容是指对同一记录的锁的兼容情况。

  • 此外InnoDB 支持多粒度的锁定的锁定,这种锁定允许事务在行级上的锁和表级上的锁同时存在,为了支持在不同粒度上进行加锁操作,InnoDB存储引擎支持一种额外的锁方式,称之为意向锁。
  • 意向锁—是将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度上进行加锁,
  • 如果我们需要对最细粒度的对象进行上锁,那么首先需要对粗粒度的对象上锁,【数据库>表>页>记录】
  • InnoDB 支持两种意向锁【表级别的锁】:
  • 意向共享锁【IS Lock】:事务想要获得一张表中某几行的共享锁。
  • 意向排他锁【IX Lock】: 事务想要获得一张表中某几行的排他锁。
    由于InnoDB支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫描以外的任何请求。
  • 表级意向锁和行级锁的兼容性如下:
ISIXSX
IS兼容兼容兼容不兼容
IX兼容兼容不兼容不兼容
S兼容不兼容兼容不兼容
X不兼容不兼容不兼容不兼容
3、一致性非锁定读
  • 一致性非锁定读指的是InnoDB存储引擎通过行多版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据。
  • 如果读取的行正在执行Delete 或者 update 操作,这时读取操作不会因此去等待行上锁的释放。

  • 相反的,InnoDB 存储引擎会去读取行的一个快照数据【读取快照数据是不需要上锁的】。-----快照数据是指该行的之前版本的数据,通过undo 段来实现,而undo段用来在事务中回滚数据,因此快照数据本身没有额外的开销。

  • 叫做非锁定读的原因是: 因为不需要等待访问的行上的 X 锁释放

  • 非锁定读机制提高了数据库的并发性。—》这是InnoDB 存储引擎默认的读取方式。读取不会占用和等待表上的锁。


  • 注意:
    1.不同事物隔离级别下-读取的方式不同,并不是在每个事务隔离级别下都采用非锁 定的一致性读。
    2.此外,就算是都使用非锁定的一致性读,但是对于快照数据的定义也各不相同。

    快照数据其实就是当前行数据之前的历史版本,每行记录可能有多个版本。而且一个行记录可能有不止一个快照数据。一般称这种技术为行多版本控制技术。由此带来的并发控制,称之为多版本并发控制。【Multi Version Concurrency Control-----MVCC】。

4、非锁定的一致性读在RR、RC下的区别

在事务隔离级别Read Committed 和 Repeatable Read 【InnoDB 存储引擎的默认事务隔离级别】下InnoDB 存储引擎使用的是非锁定的一致性 区别就是----------- 对于快照数据的定义不同

  • RC 级别下 ,对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据【也就是说在事务中每次执行快照度都会创建快照】。

  • RR 级别下 ,对于快照数据,非一致性读总是读取事务开始时的行数据版本【就是说在事务中第一次执行快照读会创建快照,然后以后的快照读都是使用之前创建的快照,所以快照的创建时机很重要,比如我们在另外一个事务执行update操做,而第一个事务只是开启并不进行快照读,那么update后我们在第一个事务使用当前读和快照读所读取到的数据是一样的;而如果我们在第一个事务中先执行了快照读,那么在update后,当前读可以读到最新数据,而快照读读到的是之前的快照版本 ,并非是最新数据】。

5、一致性锁定读

默认配置下: RR事务隔离级别下 InnoDB 存储引擎的select操作使用一致性非锁定读。

InnoDB 存储引擎对于Select语句支持两种一致性的锁定读【Locking read】操作

  • select … for update 【X 锁】
  • select … lock in share mode 【S 锁】
    上面的语句 必须出现在事务中。
    此外,即使我们使用了一致性锁定读,但是还是可以一致性非锁定读的。
6、自增长与锁
  • 自增长在数据库中是很常见的一种属性,也是主键的首选方式。
  • InnoDB存储引擎内存结构中,对每个含有自增长值得表都有一个自增长计数器,对含有自增长计数器的表进行插入操作时,这个计数器会被初始化。

插入操作会依据这个自增长的计数器值加1赋予自增长列,这叫做 Auto-INC locking 【采用特殊的表锁机制,为了提高插入的性能,锁不是在一个事务完成后才释放,而是在完成对自增长值插入的SQL 语句后立即释放。】

  • AUTO -INC locking 弊端

虽然在一定程度上提高了并发效率,但还是有一些性能问题,首先,对于有自增长值的列的并发插入性能较差,事务必须等待前一个事务的完成(虽然不用等待事务的完成),其次,大数据量的插入会影响插入的性能,因为另一个事务中的插入会被阻塞。

  • MySQL InnoDB引擎实现的轻量级互斥量的自增长

MyISAM 存储引擎实现的是表锁,自增长不用考虑并发插入的问题,
InnoDB 存储引擎中,自增长值得列必须是索引,同时必须是索引的第一个列,如果不是则会抛出异常。

7、外键和锁
  • InnoDB 存储引擎中,对于一个外键列,如果没有显示的对这个列加索引,InnoDB 存储引擎会自动的对其加一个索引,这样就可以避免表锁。

对于外键值得插入或更新,首先需要查询父表中的记录,即select 父表,但是对于父表的select 操作,不是使用一致性非锁定读的方式,因为这样会发生数据不一致的问题,因此使用的是select …lock in share mode 方式,即主动对父表加一个S 锁,如果这时父表已经加了X 锁,子表上的操作会被阻塞。

二、锁的算法

1、行锁的三种算法
  • Record Lock :单个行记录上的锁
  • Gap Lock: 间隙锁 ,锁定一个范围,但是不包括记录本身。
  • Next key Lock :Gap Lock + Record Lock ,锁定一个范围,并且锁定记录本身。

Record Lock 总是会去锁住索引记录,如果InnoDB 存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB 存储引擎会使用隐士的主键进行锁定。
Next-Key Lock 是结合了 Record Lock 和 Gap Lock 的一种锁定算法,在Next-Key Lock 算法下 ,InnoDB 对于行的查询都是采用这种锁定算法。【Next-Key Lock 是为了解决Phantom Problem】。

  • 利用这种锁定技术,锁定的不是单个值,而是一个范围,是predict lock 的一种改进,除了next-key locking 还有一种previous-key locking 技术。
  • 当查询的索引含有唯一属性时,InnoDB存储引擎会对Next -key locking 进行优化,将其降级为 Record Lock ,即仅锁住索引本身,而不是范围。
  • RC级别下会关闭 Gap Lock。
  • 默认的事务隔离级别下,即RR下 ,InnoDB 存储引擎采用Next - key Locking机制来避免Phantom Problem【幻像问题----是指在同一事务下,连续两次执行同样的SQL语句,可能导致不同的结果,第二次的SQL 语句可能会返回之前不存在的行】。

InnoDB 存储引擎采用Next-Key Locking的算法避免Phantom Problem ,比如 select * from goods where id > 5; 其锁住的不是5这条记录,而是对(5,+ oo)这个范围加了X 锁,因此对于任何这个范围的插入都是不被允许的,从而避免Phantom Problem。

  • InnoDB 存储引擎的默认事务隔离级别是 RR,RR级别下 采取Next -Key Locking 方式加锁; 而在事务隔离级别RC 下,其仅采用Record Lock ,

如果用户通过索引查询一个值,并对该行加上一个S Lock ,即使查询的值不存在,其锁定的也是一个范围。

2、阻塞

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

  • 阻塞就会出现超时 ,但是 InnoDB 存储引擎一般不会回滚超时引发的错误异常。
3、死锁

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

4、锁升级

锁升级是指将当前锁的粒度降低。

  • 数据库可以把一个表的N 个行锁升级为一个页锁,或者将页锁升级为表锁。

InnoDB 存储引擎不存在锁升级的问题,因为其不是根据每个记录来产生行锁的,其根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式。因此不管一个事务锁住页中一个记录还是多个记录,其开销通常都是一致的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值