MySQL-锁(LOCK)

文章目录

    • [1. 锁是什么?](#1. 锁是什么?)
    • [2. 全局锁](#2. 全局锁)
      • [2.1 相关语法](#2.1 相关语法)
      • [2.2 特点](#2.2 特点)
    • [3. 表级锁](#3. 表级锁)
      • [3.1 表锁](#3.1 表锁)
        • [3.1.1 共享读锁(S)](#3.1.1 共享读锁(S))
        • [3.1.2 排它写锁(X)](#3.1.2 排它写锁(X))
      • [3.2 元数据锁(MDL)](#3.2 元数据锁(MDL))
      • [3.2 意向锁(IS、IX)](#3.2 意向锁(IS、IX))
    • [4. 行级锁](#4. 行级锁)
      • [4.1 行锁](#4.1 行锁)
    • [5. 死锁](#5. 死锁)
      • [5.1 死锁检测](#5.1 死锁检测)
      • [5.2 避免死锁](#5.2 避免死锁)

1. 锁是什么?

  • 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。
  • MySQL中的锁,为了尽可能提高数据库的并发量,每次锁定的数据范围越小越好,越小的锁其耗费的系统资源越多,系统性能下降 。为在高并发响应和系统性能两方面进行平衡,这样就产生了"锁粒度"的概念。 按照锁的粒度分,分为以下三类:
    1. 全局锁:锁定数据库中的所有表。
    2. 表级锁:每次操作锁住整张表。
    3. 行级锁:每次操作锁住对应的行数据。
  • 从锁的角度来说,表级锁适合以查询为主,只有少量按索引条件更新数据的应用,如 Web 应用。而行级锁更适合于有大量按索引条件,同时又有并发查询的应用,如一些在线事务处理( OLTP)系统。

2. 全局锁

  • 全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。

    对数据库进行进行逻辑备份之前,先对整个数据库加上全局锁,一旦加了全局锁之后,其他的DDL、DML全部都处于阻塞状态,但是可以执行DQL语句,也就是处于只读状态,而数据备份就是查询操作。那么数据在进行逻辑备份的过程中,数据库中的数据就是不会发生变化的,这样就保证了数据的一致性和完整性。

2.1 相关语法

  1. 加全局锁:

    mysql 复制代码
    flush tables with read lock ;
  2. 数据备份:

    mysql 复制代码
    mysqldump -uroot --p1234 db_name > db_name.sql
  3. 释放锁:

    mysql 复制代码
    unlock tables ;

2.2 特点

  • 数据库中加全局锁,是一个比较重的操作,存在以下问题:

    • 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆

    • 如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟

      在InnoDB引擎中,我们可以在备份时加上参数 --single-transaction 参数来完成不加锁的一致性数据备份。

      mysql 复制代码
      mysqldump --single-transaction -uroot --p123456 db_name > db_name.sql

3. 表级锁

3.1 表锁

  • 对于表锁,分为两类:表共享读锁(read lock)表排它写锁(write lock)

  • 语法:

    • 加锁:

      mysql 复制代码
      lock tables 表名... read/write
    • 释放锁:

      mysql 复制代码
      unlock tables
3.1.1 共享读锁(S)
  • 共享锁的代号是 S ,是 Share 的缩写,也可称为读锁。是一种可以查看但无法修改和删除的数据锁。

  • 共享锁的锁粒度是行或者元组(多个行)。一个事务获取了共享锁之后,可以对锁定范围内的数据执行读操作。会阻止其它事务获得相同数据集的排他锁。简单来说就是获得读锁的事务A与其他事务B都可以对锁范围内的数据进行读操作,但都不能进行写操作。

3.1.2 排它写锁(X)
  • 排他锁的代号是 X ,是 eXclusive 的缩写,也可称为写锁,是基本的锁类型。

  • 排他锁的粒度与共享锁相同,也是行或者元组。一个事务获取了排他锁之后,可以对锁定范围内的数据执行写操作。允许获得排他锁的事务更新数据,阻止其它事务取得相同数据集的共享锁和排他锁。简单来说就是获得写锁的事务A可以对锁范围内的数据进行读和写,但其他事务B不能对锁范围内的数据进行读和写。

3.2 元数据锁(MDL)

  • meta data lock , 元数据锁,简写MDL。MDL加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性。这里的元数据,大家可以简单理解为就是一张表的表结构。 也就是说,某一张表涉及到未提交的事务时,是不能够修改这张表的表结构的

  • 在MySQL5.5中引入了MDL,当对一张表进行增删改查的时候,加MDL读锁(共享);当对表结构进行变更操作的时候,加MDL写锁(排他)。

  • 常见的SQL操作时,所添加的元数据锁:

    对应SQL 锁类型 说明
    lock tables xxx read / write SHARED_READ_ONLY / SHARED_NO_READ_WRITE
    select 、select ... lock in share mode SHARED_READ 与SHARED_READ、 SHARED_WRITE兼容,与 EXCLUSIVE互斥
    insert 、update、 delete、select ... for update SHARED_WRITE 与SHARED_READ、 SHARED_WRITE兼容,与 EXCLUSIVE互斥
    alter table ... EXCLUSIVE 与其他的MDL都互斥

3.2 意向锁(IS、IX)

  • 为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB 还有两种内部使用的意向锁。意向锁是一种表锁,锁定的粒度是整张表,分为**意向共享锁( IS)意向排他锁( IX)**两类。

  • 添加意向共享锁:

    mysql 复制代码
    select ... lock in share mode
  • 添加意向排它锁:

    mysql 复制代码
    insert、update、delete、select...for update
  • 其中共享锁排他锁意向共享锁意向排他锁相互之间的兼容/互斥关系如下表所示,其中 Y 表示相容, N 表示互斥。

    参数 X S IX IS
    X(排他锁) N N N N
    S(共享锁) N Y N Y
    IX(意向排他锁) N N Y Y
    IS(意向共享锁) N Y Y Y

    如果一个事务请求的锁模式与当前的锁兼容, InnoDB 就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。

4. 行级锁

  • 在 MySQL 中, InnoDB 行锁通过给索引上的索引项加锁来实现,如果没有索引, InnoDB 将通过隐藏的聚簇索引来对记录加锁。

  • InnoDB的行锁是针对于索引加的锁,如果不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,此时就会升级为表锁。

  • InnoDB 支持 3 种行锁定方式:

    1. 行锁( Record Lock):直接对索引项加锁。

      mysql 复制代码
      select * from student where id = 1 for update;
    2. 间隙锁( Gap Lock):锁加在索引项之间的间隙,也可以是第一条记录前的"间隙"或最后一条记录后的"间隙"。

      mysql 复制代码
      select * from student where id > 2 and id < 5 for update;
    3. Next-Key Lock :行锁与间隙锁组合起来用就叫做 Next-Key Lock。 前两种的组合,对记录及其前面的间隙加锁

      mysql 复制代码
      select * from student where id > 4 for update;

4.1 行锁

  • InnoDB实现了以下两种类型的行锁:

    1. 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。
    2. 排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。
  • 常见的SQL语句,在执行时,所加的行锁如下:

    SQL 行锁类型 说明
    INSERT ... 排他锁 自动加锁
    UPDATE ... 排他锁 自动加锁
    DELETE ... 排他锁 自动加锁
    SELECT(正常) 不加任何 锁
    SELECT ... LOCK IN SHARE MODE 共享锁 需要手动在SELECT之后加LOCK IN SHARE MODE
    SELECT ... FOR UPDATE 排他锁 需要手动在SELECT之后加FOR UPDATE

5. 死锁

  • 定义:死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。 就是所谓的锁资源请求产生了回路现象,即死循环,此时称系统处于死锁状态或系统产生了死锁。常见的报错信息为"Deadlock found when trying to get lock..."。
  • 解决方案:死锁发生以后,只有部分或完全回滚其中一个事务,才能打破死锁。多数情况下只需要重新执行因死锁回滚的事务即可。

5.1 死锁检测

  • InnoDB的并发写操作会触发死锁,同时 InnoDB 也提供了死锁检测机制。通过设置 innodb_deadlock_detect 参数的值来控制是否打开死锁检测。
  1. innodb_deadlock_detect = ON默认值,打开死锁检测。数据库发生死锁时,系统会自动回滚其中的某一个事务, 让其它事务可以继续执行。

  2. innodb_deadlock_detect = OFF:关闭死锁检测。发生死锁时,系统会用锁等待来处理。

    锁等待是指在事务过程中产生的锁,其它事务需要等待上一个事务释放锁,才能占用该资源。如果该事务一直不释放,就需要持续等待下去,直到超过了锁等待时间。 当超过锁等待允许的最大时间,就会出现死锁,然后当前事务执行失败,自动执行回滚操作。

5.2 避免死锁

  • 在实际应用中,我们要尽量防止锁等待现象的发生,下面介绍几种避免死锁的方法:
    1. 如果不同程序会并发存取多个表,或者涉及多行记录时,尽量约定以相同的顺序访问表 ,这样可以大大降低死锁的发
      生。
    2. 业务中要及时提交或者回滚事务,可减少死锁产生的概率。
    3. 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率。
    4. 对于非常容易产生死锁的业务部分,可以尝试使用升级锁粒度,通过表锁定来减少死锁产生的概率(表级锁不会产生死锁)。
相关推荐
时差9531 小时前
【面试题】Hive 查询:如何查找用户连续三天登录的记录
大数据·数据库·hive·sql·面试·database
让学习成为一种生活方式1 小时前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
秋意钟1 小时前
MySQL日期类型选择建议
数据库·mysql
Dxy12393102162 小时前
python下载pdf
数据库·python·pdf
ac-er88882 小时前
MySQL如何实现PHP输入安全
mysql·安全·php
桀桀桀桀桀桀3 小时前
数据库中的用户管理和权限管理
数据库·mysql
superman超哥4 小时前
04 深入 Oracle 并发世界:MVCC、锁、闩锁、事务隔离与并发性能优化的探索
数据库·oracle·性能优化·dba
用户8007165452004 小时前
HTAP数据库国产化改造技术可行性方案分析
数据库
engchina5 小时前
Neo4j 和 Python 初学者指南:如何使用可选关系匹配优化 Cypher 查询
数据库·python·neo4j
engchina5 小时前
使用 Cypher 查询语言在 Neo4j 中查找最短路径
数据库·neo4j