MySQL进阶_10.锁

文章目录

  • 一、概述
  • 二、MySQL并发事务访问相同记录
    • 2.1、读-读
    • 2.2、写-写
    • 2.3、读-写
    • 2.4、并发问题的解决方案
  • 三、锁的不同角度分类
    • 3.1、 读锁、写锁
      • 3.1.1、 锁定读
    • 3.2、表级锁、页级锁、行锁
      • 3.2.1、表锁
      • 3.2.2、意向锁
        • 3.2.2.1、意向锁的作用
        • 3.2.2.2、意向锁的互斥性
      • 3.2.3、自增锁(AUTO-INC锁)
      • 3.2.4、元数据锁(MDL锁)

一、概述

在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。为保证数据的一致性,需要对 并发操作进行控制 ,因此产生了 。同时 锁机制 也为实现MySQL的各个隔离级别提供了保证。 锁冲突 也是影响数据库 并发访问性能 的一个重要因素。所以锁对数据库而言显得尤其重要,也更加复杂。

二、MySQL并发事务访问相同记录

并发事务访问相同记录的情况大致可以划分为3种

2.1、读-读

读-读 情况,即并发事务相继 读取相同的记录 。读取操作本身不会对记录有任何影响,并不会引起什么问题,所以允许这种情况的发生

2.2、写-写

有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失第二类更新丢失

2.3、读-写

有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读幻读不可重复读

2.4、并发问题的解决方案

怎么解决 脏读 、 不可重复读 、 幻读 这些问题呢?其实有两种可选的解决方案

  1. 读操作利用多版本并发控制( MVCC ),写操作进行 加锁
  2. 读、写操作都采用 加锁 的方式

采用 MVCC 方式的话, 读-写 操作彼此并不冲突, 性能更高。采用 加锁 方式的话, 读-写 操作彼此需要 排队执行 ,影响性能。

三、锁的不同角度分类

MySQL进阶_10.锁_第1张图片

3.1、 读锁、写锁

  • 读锁 :也称为 共享锁 、英文用 S 表示。针对同一份数据,多个事务的读操作可以同时进行而不会互相影响,相互不阻塞的。
  • 写锁 :也称为 排他锁 、英文用 X 表示。当前写操作没有完成前,它会阻断其他写锁和读锁。这样就能确保在给定的时间里,只有一个事务能执行写入,并防止其他用户读取正在写入的同一资源。

需要注意的是对于 InnoDB 引擎来说,读锁和写锁可以加在表上,也可以加在行上

3.1.1、 锁定读

SELECT ... LOCK IN SHARE MODE;
#或
SELECT ... FOR SHARE; #(8.0新增语法)

在普通的SELECT语句后边加LOCK IN SHARE MODE,如果当前事务执行了该语句,那么它会为读取到的记录加S锁。

SELECT ... FOR UPDATE;

在普通的SELECT语句后边加FOR UPDATE,如果当前事务执行了该语句,那么它会为读取到的记录加X锁。这样既不允许别的事务获取这些记录的S锁,也不允许获取这些记录的X锁。如果别的事务想获取这些记录的S锁或X锁,那么它们会阻塞,直到当前事务提交之后将这些记录上的X锁释放掉。

3.2、表级锁、页级锁、行锁

  为了尽可能提高数据库的并发度,每次锁定的数据范围越小越好,理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但是管理锁是很耗资源的事情(涉及获取、检查、释放锁等动作)。因此数据库系统需要在高并发响应系统性能两方面进行平衡,这样就产生了“锁粒度(Lock granularity)”的概念。
  对一条记录加锁影响的也只是这条记录而已,我们就说这个锁的粒度比较细;其实一个事务也可以在表级别进行加锁,自然就被称之为表级锁或者表锁,对一个表加锁影响整个表中的记录,我们就说这个锁的粒度比较粗。锁的粒度主要分为表级锁、页级锁和行锁。

3.2.1、表锁

MySQL进阶_10.锁_第2张图片

3.2.2、意向锁

3.2.2.1、意向锁的作用

  InnoDB 支持 多粒度锁(multiple granularity locking) ,它允许 行级锁表级锁 共存,而意向锁就是能和行级锁共存的一种 表锁

意向锁解决的问题是:
  现在有两个事务,分别是T1和T2,其中T2试图在该表级别上应用共享或排它锁,如果没有意向锁存在,那么T2就需要去检查各个页或行是否存在锁(假设表中数据有100000行,是很费时间的);如果存在意向锁,那么此时就会受到由T1控制的表级别意向锁的阻塞。T2在锁定该表前不必检查各个页或行锁,而只需检查表上的意向锁。简单来说就是给更大一级别的空间示意里面是否已经上过锁。
  在数据表的场景中,如果我们给某一行数据加上了排它锁,数据库会自动给更大一级的空间,比如数据页或数据表加上意向锁,告诉其他人这个数据页或数据表已经有人上过排它锁了,这样当其他人想要获取数据表排它锁的时候,只需要了解是否有人已经获取了这个数据表的意向排他锁即可。

意向锁分为两种:

  • 意向共享锁(intention shared lock, IS):事务有意向对表中的某些行加共享锁(S锁)
-- 事务要获取某些行的 S 锁,必须先获得表的 IS 锁。
SELECT column FROM table ... LOCK IN SHARE MODE;

-- 假设本次查询只对三条数据加了S锁,InnoDB会自动给该表加IS锁
  • 意向排他锁(intention exclusive lock, IX):事务有意向对表中的某些行加排他锁(X锁)
-- 事务要获取某些行的 X 锁,必须先获得表的 IX 锁。
SELECT column FROM table ... FOR UPDATE;

即:意向锁是由存储引擎 自己维护的 ,用户无法手动操作意向锁,在为数据行加共享 / 排他锁之前,InooDB 会先获取该数据行 所在数据表的对应意向锁

3.2.2.2、意向锁的互斥性

在这里插入图片描述
即意向锁之间是互相兼容的,虽然意向锁和自家兄弟互相兼容,但是它会与普通的排他/共享锁互斥。

在这里插入图片描述
注意这里的排他/共享锁指的都是表锁意向锁不会与行级的共享/排他锁互斥
IX,IS是表级锁,不会和行级的X,S锁发生冲突。只会和表级的x,s发生冲突。

3.2.3、自增锁(AUTO-INC锁)

本次学习不做了解。

3.2.4、元数据锁(MDL锁)

你可能感兴趣的:(MySQL,mysql,锁,行锁,表锁)