MySQL锁相关——锁机制、表锁、行锁、死锁、锁优化等

2023-12-27 05:36

本文主要是介绍MySQL锁相关——锁机制、表锁、行锁、死锁、锁优化等,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.锁机制

(1)共享锁和排他锁

  • 共享锁(S Lock):其他事务可读,但不可写
  • 排他锁(X Lock):其他事务不能读取也不能写

(2)粒度锁

从粒度上来说,可以将锁分为全局锁、表锁、页锁和行锁

  • 全局锁:可以锁定整个数据库系统,阻止其他事务对数据库进行写入或修改操作。当一个事务获取到全局锁时,其他事务将无法执行任何对数据库写入的操作,直到全局锁被释放。
-- 全局锁,整个数据库处于只读状态,其他操作均阻塞
FLUSH TABLES WITH READ LOCK-- 释放全局锁
UNLOCK TABLES
  • 表锁:用于锁定整个表,控制对表的并发访问。当一个事务获取到表级锁时,其他事务将被阻塞,无法同时对该表进行写操作或修改操作。
mysql> LOCK TABLES 表名 READ|WRITE;mysql> UNLOCK TABLES
  • 行锁:行级锁的类型有 - 记录锁,也就是仅仅把一条(行)记录锁上; - 间隙锁,锁定一个范围,但是不包含记录本身; - 临键锁:记录锁 + 间隙锁的组合,锁定一个范围,并且锁定记录本身。
  • 页锁:页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。

【注意】MySQL不同的存储引擎支持不同的锁机制,所有存储引擎都以自己的方式显现了锁机制,服务器层完全不了解存储引擎中的锁实现。默认情况下表锁和行锁都是自动获得的,不需要额外的命令,但某些情况下用户需要明确的进行行锁或进行事务的控制,以便确保整个事务的完整性,这样就需要使用事务控制和锁定语句来完成。

2.MyISAM表锁

(1)MyISAM表级锁模式

  • 表共享读锁:不会阻塞其他用户对同一表的读操作,但会阻塞同一表的写请求
  • 表独占写锁:会阻塞其他用户对同一表的读写操作
    select自动加读锁,其他DML、DDL自动加写锁。

默认情况下,写锁比读锁具有更高的优先级:当一个锁释放时,这个锁会优先给写锁队列中等候的获取锁请求,然后再给读锁队列中等候的获取锁请求。(因此MyISAM表不适用于有大量更新操作和查询操作的应用,因为大量的更新操作会造成查询操作很难获取读锁,从而可能永远阻塞)

可以设置参数low-priority-updates,使MyISAM引擎默认给予读请求优先的权利。

(2)加表锁方法

MyISAM在执行select语句之前会自动给涉及的表加读锁;在执行更新操作前会自动给涉及的表加写锁,这个过程不需要用户干预,因此一般不需要直接使用lock table给MyISAM表显示加锁。
自动加锁的情况下,MyISAM总是一次获得SQL语句所需要的全部锁,这也正是MyISAM表不会出现死锁的原因

(3)表级锁争用情况

可以通过检查table_lock_waitedtable_locks_immediate状态变量来分析系统上表锁的争夺,如果table_lock_waited的值比较高,则说明存在着较严重的表级锁争用情况。
在这里插入图片描述

3.InnoDB行级锁和表级锁

(1)InnoDB锁模式

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

  • 共享锁:允许一个事务去读一行,阻止其他事务获得相同的数据集的排他锁
  • 排他锁:允许获得排他锁的事务更新数据,阻止其他事务取得相同的数据集的共享读锁和排他写锁

为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁,这两种意向锁都是表锁。

  • 意向共享锁:事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的意向共享锁
  • 意向排他锁:事务打算给数据行加行排他锁,必须先取得该表的意向排他锁。

(2)InnoDB加锁方法

意向锁是InnoDB自动加的,不需用户干预:对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及的数据集加排他锁;对于普通的select语句,InnoDB不会加任何锁。

事务可以通过以下语句显式给记录集加共享锁或排他锁:

select * from table_name where ... lock in share mode;

其他session仍然可以查询记录,并也可以对该记录加share mode的共享锁,但如果当前事务需要对该记录进行更新操作,则很有可能造成死锁
在这里插入图片描述
在这里插入图片描述
select * from table_name where … for update
其他session可以查询该记录,但是不能对该记录加共享锁或排他锁,而是等待获得锁。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
select ... for update在执行这个语句的时候会将响应的索引访问条目上排他锁,也就是说这个语句对应的锁就相当于update带来的效果。
【使用场景】为确保自己查到的数据是最新数据,并且查到后的数据只允许自己来修改。
【性能影响】业务繁忙的情况下,如果没有及时commit或者rollback可能会造成其他事务长时间等待,从而影响数据库的并发使用效率

select ... lock in share mode作用是将查找的数据加上一个share锁,这个就是表示其他的事务只能对这些数据进行简单的select操作,并不能够进行DML操作
【使用场景】确保自己查到的数据没有被其他事务正在修改,确保查到的数据是最新数据。但自己不一定能修改数据,因为有可能其他事务对这些数据使用了in share mode的方式上了S锁。
【性能影响】如果没有及时commit或者rollback可能会造成其他事务长时间等待

(3)InnoDB行锁的实现方式

InnoDB行锁是通过给索引上的索引项加锁来实现的(Oracle是在数据库块中对相应数据行加锁实现)。【意味着】InnoDB只有通过索引条件检索数据才使用行级锁,否则使用表锁。
只有执行计划真正使用了索引才会使用行锁。

(4)InnoDB间隙锁

当使用范围条件而不是相等条件检索数据并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项枷锁;对于键值在条件范围内但不并不存在的记录叫做“间隙”,InnoDB也会对这个间隙加锁,这种机制叫间隙锁。
显然,这种加锁机制会阻塞符合条件范围内键值的并发插入,往往会造成严重的锁等待。因此实际开发中,尤其是并发插入比较多的应用,应尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。

间隙锁的【目的】:防止幻读,满足相关隔离级别要求;满足恢复和复制的需要。

(5)InnoDB行锁争用情况

可以通过检查InnoDB_row_lock状态变量来分析系统上的行锁争夺情况:
在这里插入图片描述
Innodb_row_lock_waits和innodb_row_lock_avg的值来判断行锁争用情况,值高意味着竞争比较严重。Innodb_row_lock_waits指系统启动到现在总共在等待的次数。

4.LOCK TABLES和UNLOCK TABLES

单表加写锁:lock table tb_name write;
其他线程不能对该表进行读写操作,当前线程可以读写
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
单表加读锁:lock table tb_name read;(本线程只能读,其他线程也只能读)
在这里插入图片描述
在这里插入图片描述

5.死锁和锁优化

【产生原因】两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源从而导致恶行循环。多个事务同时锁定同一个资源是也可能会产生死锁。
【死锁检测】

  • 超时法:如果一个事务的等待时间超过规定时间则认为发生了死锁,但这种方式可能会误判死锁,并且若超时时间设置过大可能造成死锁不能及时发现
  • 等待图法:事务等待动图反映了所有事物的等待情况。并发控制子系统周期性生成事务等待图并进行检测。如果发现图中存在回路则表示出现死锁
    【避免】
  • MyISAM避免死锁:在自动加锁的情况下,MyISAM总是一次性获得SQL语句所需的全部锁,因此不会出现死锁
  • InnoDB避免死锁:
    ① 事务开始时通过为与其要修改的每行使用select … for update语句来获取必要的锁,即使这些更改语句是在之后才执行的。
    ② 在事务中如果要更新记录,直接申请足够级别的锁(排他锁),不应该先申请共享锁再申请排他锁(容易造成锁冲突)
    ③ 事务如果要修改或锁定多个表,应该再每个事务中以相同的顺序使用加锁语句
    ④ 通过select … lock share mode获取行的读锁后,如果当前事务再需要对该记录进行更新操作,很有可能造成死锁。

【锁优化】
A.精心设计索引,并尽量使用索引来访问数据,使锁更加精确从而减少所冲突的机会
B.选择合理的事务大小,小事务发生所冲突的几率也更小
C.最好一次性请求足够级别的锁(修改数据直接申请排他锁)
D.不同程序访问一组表时,尽量约定以相同的顺序访问各表
E.尽量使用相等条件访问数据,这样可以避免间隙锁对并发插入的影响
F.除非必须,查询时不显示加锁
G.对于一些特定的事务可以使用表锁来提高处理速度或减少死锁的可能

【MySQL的解决方案】
A.增加锁超时时间,MySQL默认的等待时间为50秒,设置较高的锁超时时间可以避免死锁问题的发生
B.优化事务,事务中应避免使用长时间的锁等待
C.使用InnoDB引擎,支持行级锁定,减少锁定范围,可以更精细地控制锁定的资源

【MySQL死锁检测】
A.SHOW ENGINE INNODB STATUS命令,在结果中查找“LATEST DETECTED DEADLOCK”关键字,如果存在该关键字,则表示存在死锁
B.查看当前未提交的事务(如果死锁等待超时,事务可能还没有关闭)
select * from information_schema.INNODB_TRX;
C.查看正在被访问的表
show open tables where in_use > 0;
D.查看当前出现的锁
select * from performance_schema.data_locks;
E.查看锁等待对应关系
select * from performance_schema.data_lock_waits;
F.死锁记录默认只记录最近一个死锁信息,若要将每个死锁信息都保存到错误日志,启用以下参数:
在这里插入图片描述
G.查看行锁信息:
show status like ‘innodb_row_lock_%’;

6.乐观锁、悲观锁和其他锁

  • 乐观锁:假设并不会发生冲突,只在提交时检查是否违反数据完整行。乐观锁不能解决脏读问题。
  • 悲观锁:假设会发生冲突,屏蔽一切可能违反数据完整性的操作
  • 其他锁:
    ① 全局锁
    global read lock
    加锁:FLUSH TABLES WITH READ LOCK
    关闭实例下所有表,并加上全局读锁,防止被修改,直到提交UNLOCK TABLES
    【用途】一般用于备份,mysqldump和xtrabackup都会发起。

query cache lock
对QC中的数据有更新时,都会引发query cache lock

② MDL锁
meta data lock,事务内对库、表、procedure、function、triggers、event、tablespace等多种对象上加的锁。
事务开启后,会锁定表的meta data lock,其他会话对表有DDL操作时,均需等待MDL释放后执行。

这篇关于MySQL锁相关——锁机制、表锁、行锁、死锁、锁优化等的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/542023

相关文章

MySQL安装时initializing database失败的问题解决

《MySQL安装时initializingdatabase失败的问题解决》本文主要介绍了MySQL安装时initializingdatabase失败的问题解决,文中通过图文介绍的非常详细,对大家的学... 目录问题页面:解决方法:问题页面:解决方法:1.勾选红框中的选项:2.将下图红框中全部改为英

MySQL 中的服务器配置和状态详解(MySQL Server Configuration and Status)

《MySQL中的服务器配置和状态详解(MySQLServerConfigurationandStatus)》MySQL服务器配置和状态设置包括服务器选项、系统变量和状态变量三个方面,可以通过... 目录mysql 之服务器配置和状态1 MySQL 架构和性能优化1.1 服务器配置和状态1.1.1 服务器选项

MySQL8.0设置redo缓存大小的实现

《MySQL8.0设置redo缓存大小的实现》本文主要在MySQL8.0.30及之后版本中使用innodb_redo_log_capacity参数在线更改redo缓存文件大小,下面就来介绍一下,具有一... mysql 8.0.30及之后版本可以使用innodb_redo_log_capacity参数来更改

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

oracle DBMS_SQL.PARSE的使用方法和示例

《oracleDBMS_SQL.PARSE的使用方法和示例》DBMS_SQL是Oracle数据库中的一个强大包,用于动态构建和执行SQL语句,DBMS_SQL.PARSE过程解析SQL语句或PL/S... 目录语法示例注意事项DBMS_SQL 是 oracle 数据库中的一个强大包,它允许动态地构建和执行

SQL 中多表查询的常见连接方式详解

《SQL中多表查询的常见连接方式详解》本文介绍SQL中多表查询的常见连接方式,包括内连接(INNERJOIN)、左连接(LEFTJOIN)、右连接(RIGHTJOIN)、全外连接(FULLOUTER... 目录一、连接类型图表(ASCII 形式)二、前置代码(创建示例表)三、连接方式代码示例1. 内连接(I

在MySQL执行UPDATE语句时遇到的错误1175的解决方案

《在MySQL执行UPDATE语句时遇到的错误1175的解决方案》MySQL安全更新模式(SafeUpdateMode)限制了UPDATE和DELETE操作,要求使用WHERE子句时必须基于主键或索引... mysql 中遇到的 Error Code: 1175 是由于启用了 安全更新模式(Safe Upd

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri

Deepseek使用指南与提问优化策略方式

《Deepseek使用指南与提问优化策略方式》本文介绍了DeepSeek语义搜索引擎的核心功能、集成方法及优化提问策略,通过自然语言处理和机器学习提供精准搜索结果,适用于智能客服、知识库检索等领域... 目录序言1. DeepSeek 概述2. DeepSeek 的集成与使用2.1 DeepSeek API