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

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

如何去写一手好SQL

MySQL性能 最大数据量 抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。 《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。 博主曾经操作过超过4亿行数据

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始