MySQL锁机制详解

news2024/11/27 21:33:18

概述

锁是计算机协调多个进程或线程并发访问某一资源的机制。

在数据库中,除了传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供需要用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。

锁分类

锁粒度: 表锁、页锁、行锁。

锁性质: 共享(读)锁、排他(写)锁、意向共享(读)锁、意向排他(写)锁。

锁思想: 悲观锁、乐观锁。

读锁(共享锁,S锁(Shared))

读取操作(SELECT)时创建的锁。其他用户可以并发读取数据,但在读锁未释放前,也就是查询事务结束前,任何事务都不能对数据进行修改(获取数据上的写锁),直到已释放所有读锁。

如果事务A对数据B(1024房)加上读锁后,则其他事务只能对数据B上加读锁,不能加写锁。获得读锁的事务只能读数据,不能修改数据。

针对同一份数据,多个读操作可以同时进行而不会互相影响,比如:

SELECT * FROM `user` WHERE id = 1 lock in share mode

写锁(排它锁,X锁(eXclusive))

如果事务A对数据B加上写锁后,则其他事务不能再对数据B加任何类型的锁。获得写锁的事务既能读数据,又能修改数据。

当前写操作没有完成前,它会阻断其他写锁和读锁,数据修改操作都会加写锁,查询也可以通过for update加写锁,比如:

SELECT * FROM `user` WHERE id = 1 for update

意向锁(Intention Lock)

意向锁(Intention Lock)又称I锁,针对表锁,主要是为了提高加表锁的效率,是mysql数据库自己加的。当有事务给表的数据行加了共享锁或排他锁,同时会给表设置一个标识,代表已经有行锁了,其他事务要想对表加表锁时,就不必逐行判断有没有行锁可能跟表锁冲突了,直接读这个标识就可以确定自己该不该加表锁。特别是表中的记录很多时,逐行判断加表锁的方式效率很低。而这个标识就是意向锁。

意向共享锁,IS锁,对整个表加共享锁之前,需要先获取到意向共享锁。

意向排他锁,IX锁,对整个表加排他锁之前,需要先获取到意向排他锁。

表锁

表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表定,所以可以很好的避免困扰我们的死锁问题。

使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。

每次操作锁住整张表。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;一般用在整表数据迁移的场景。

--手动增加表锁
lock table 表名称 read(write),表名称2 read(write);
--查看表上加过的锁
show open tables;
--删除表锁
unlock tables;

页锁

只有BDB存储引擎支持页锁,页锁就是在页的粒度上进行锁定,锁定的数据资源比行锁要多,因为一个页中可以有多个行记录。当我们使用页锁的时候,会出现数据浪费的现象,但这样的浪费最多也就是一个页上的数据行。页锁的开销介于表锁和行锁之间,会出现死锁。锁定粒度介于表锁和行锁之间,并发度一般。

行锁

每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。

InnoDB相对于MYISAM的最大不同有两点:

  1. InnoDB支持事务(TRANSACTION)
  2. InnoDB支持行级锁

InnoDB的行锁实际上是针对索引加的锁(在索引对应的索引项上做标记),不是针对整个行记录加的锁。并且该索引不能失效,否则会从行锁升级为表锁。(RR级别会升级为表锁,RC级别不会升级为表锁)

select * from account where name = 'lilei' for update;   
#where条件里的name字段无索引则其它Session对该表任意一行记录做修改操作都会被阻塞住。

关于RR级别行锁升级为表锁的原因分析:

因为在RR隔离级别下,需要解决不可重复读和幻读问题,所以在遍历扫描聚集索引记录时,为了防止扫描过的索引被其它事务修改(不可重复读问题) 或 间隙被其它事务插入记录(幻读问题),从而导致数据不一致,所以MySQL的解决方案就是把所有扫描过的索引记录和间隙都锁上,这里要注意,并不是直接将整张表加表锁,因为不一定能加上表锁,可能会有其它事务锁住了表里的其它行记录。

间隙锁(Gap Lock)

间隙锁,锁的就是两个值之间的空隙,间隙锁是在可重复读隔离级别下才会生效。

Mysql默认级别是repeatable-read,有幻读问题,间隙锁是可以解决幻读问题的。

account表数据如下:

在这里插入图片描述
那么间隙就有 id 为 (3,10),(10,20),(20,30),(30,正无穷) 这四个区间。

如果执行下面这条sql:

BEGIN;

SELECT * FROM account WHERE id = 18 for UPDATE;

#COMMIT;

则其他Session没法在这个(20,30)这个间隙范围里插入任何数据。
也就是说,只要在间隙范围内锁了一条不存在的记录会锁住整个间隙范围,不锁边界记录,这样就能防止其它Session在这个间隙范围内插入数据,就解决了可重复读隔离级别的幻读问题。

临键锁(Next-key Locks)

Next-Key Locks是行锁与间隙锁的组合。

总结

MyISAM在执行查询语句SELECT前,会自动给涉及的所有表加读锁,在执行update、insert、delete操作会自动给涉及的表加写锁。

InnoDB在执行查询语句SELECT时(非串行隔离级别),不会加锁。但是update、insert、delete操作会加行锁。
另外,读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞。

Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一下,但是在整体并发处理能力方面要远远优于MYISAM的表级锁定的。当系统并发量高的时候,Innodb的整体性能和MYISAM相比就会有比较明显的优势了。

但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让Innodb的整体性能表现不仅不能比MYISAM高,甚至可能会更差。

锁等待分析

通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况

show status like 'innodb_row_lock%';

对各个状态量的说明如下:
Innodb_row_lock_current_waits: 当前正在等待锁定的数量
Innodb_row_lock_time: 从系统启动到现在锁定总时间长度
Innodb_row_lock_time_avg: 每次等待所花平均时间
Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花时间
Innodb_row_lock_waits: 系统启动后到现在总共等待的次数

对于这5个状态变量,比较重要的主要是:
Innodb_row_lock_time_avg (等待平均时长)
Innodb_row_lock_waits (等待总次数)
Innodb_row_lock_time(等待总时长)

尤其是当等待次数很高,而且每次等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,然后根据分析结果着手制定优化计划。

查看INFORMATION_SCHEMA系统库锁相关数据表

-- 查看事务
select * from INFORMATION_SCHEMA.INNODB_TRX;
-- 查看锁,8.0之后需要换成这张表performance_schema.data_locks
select * from INFORMATION_SCHEMA.INNODB_LOCKS;  
-- 查看锁等待,8.0之后需要换成这张表performance_schema.data_lock_waits
select * from INFORMATION_SCHEMA.INNODB_LOCK_WAITS;  

-- 释放锁,trx_mysql_thread_id可以从INNODB_TRX表里查看到
kill trx_mysql_thread_id

-- 查看锁等待详细信息
show engine innodb status; 

死锁问题分析

set tx_isolation='repeatable-read';
Session_1执行:select * from account where id=1 for update;
Session_2执行:select * from account where id=2 for update;
Session_1执行:select * from account where id=2 for update;
Session_2执行:select * from account where id=1 for update;
查看近期死锁日志信息:show engine innodb status; 

大多数情况mysql可以自动检测死锁并回滚产生死锁的那个事务,但是有些情况mysql没法自动检测死锁,这种情况我们可以通过日志分析找到对应事务线程id,可以通过kill杀掉。

锁优化实践

尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁。
合理设计索引,尽量缩小锁的范围。
尽可能减少检索条件范围,避免间隙锁。
尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行。
尽可能用低的事务隔离级别。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1207559.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设备管理平台能做什么?企业如何做好设备维护管理工作?

在当今高度数字化的时代,企业运营离不开各种设备的支持。如何确保这些设备高效运转,降低故障率,成为了企业运营的关键问题。为此,设备管理平台应运而生,它借助数字化、移动互联网等技术,为企业提供全方位的…

kube-bench-CIS基准的自动化扫描工具学习

仓库地址:GitHub - aquasecurity/kube-bench: Checks whether Kubernetes is deployed according to security best practices as defined in the CIS Kubernetes Benchmark kube-bench,检查 Kubernetes 是否根据 CIS Kubernetes 基准中定义的安全最佳实践部署,下载…

%与floormod方法区别

%求余数 计算步骤: 10 / -3 -3.333333........... %是向0方向取整,因此-3.3333.......取整数-3 10 % -3 10-(-3*-3) 1 floormod方法 计算步骤:floormod(10,-3) floormod是向负无穷方向取整,因此-3…

C#使用时序数据库 InfluxDB

一、安装 https://docs.influxdata.com/influxdb/v2/install/?tWindows 解压后使用cmd运行 访问 localhost:8086 配置 第一次登入会初始化 配置登入账号 保存TOKEN 这个TOKEN用于后期代码链接访问数据库,忘记了只能删除重新生成 点击QUCK START进入管理页面 …

全球市场的新趋势:海外网红营销和私域流量的共同驱动

在数字时代的今天,随着全球互联网的蓬勃发展,网络营销已经不再是一种新鲜事物。然而,随着社交媒体和在线内容创作的兴起,一种新的营销方式崭露头角,它将海外网红营销与私域流量相结合,成为了全球市场的一股…

Leetcode 236 二叉树的最近公共祖先

/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val x; }* }*///用f(x)表示x节点的子树是否包含p或者q//则满足公共祖先节点有两种情况组成//1.f(x.left) && f(x…

RT-DETR算法优化改进:Backbone改进 | VanillaNet一种新视觉Backbone,极简且强大!华为诺亚2023

💡💡💡本文独家改进: VanillaNet助力RT-DETR ,替换backbone,简到极致、浅到极致!深度为6的网络即可取得76.36%@ImageNet的精度,深度为13的VanillaNet甚至取得了83.1%的惊人性能。 推荐指数:五星 RT-DETR魔术师专栏介绍: https://blog.csdn.net/m0_63774211/cat…

后端接口性能优化分析-2

常见思路 1.批量思想: 这个其实是一个最容易想到的代码层次的修改,其实对业务上来说,结果都是一样的,只不过这个涉及到了一件事就是,像数据库中发请求,是发十次还是发一次的问题。其原因最根本的还是&…

C++ VS2015安装教程,下载和安装(下载地址+图解+详细步骤)

说明:VS2015的三个版本分别为: Visual Studio Community(社区版):满足大部分程序员的需求(推荐) Visual Studio Professional(专业版) Visual Studio Enterprise(企业版) 1、下载地址(这里只提供Community版) htt…

修炼k8s+flink+hdfs+dlink(七:flinkcdc)

一 :flinkcdc官网链接。 https://ververica.github.io/flink-cdc-connectors/release-2.1/content/about.html 二:在flink中添加jar包。 在flink lib目录下增加你所需要的包。 https://kdocs.cn/join/gv467qi?f101 邀请你加入共享群「工作使用重要工具…

java中常见的设计模式

最早概念是在建筑领域产生的,后来被引入到软件开发领域。 模式是解决一类问题的固定写法,一个模式用来解决一种问题,经过反复优化,最终得出来的。之前的程序员们,在工作中对某一类问题解决方式进行总结归纳&#xff0…

终端神器:tmux

安装tmux简单使用自己的理解(小白专属) 使用的初衷: 在Linux终端下,由于session(会话)和windows(窗口)是绑定一起的,你打开一个终端的黑窗口就是打开一个会话&#xff0c…

sinc 函数

See https://wuli.wiki/online/sinc.html 公式(3)的证明见 https://wuli.wiki/online/JdLem.html#ex_JdLem_1 百度百科

git快速上传代码

① git init; 初始化git,之后在文件夹里有.git文件,这个需要 勾选才能查看。 ② git remote add test myFisrtTest: 测试专用 这里的test是自定义的,myFisrtTest: 测试专用 是远程仓库 ③ git branch -a 这里是查看分支 ④ …

好消息!2023年汉字小达人市级比赛在线模拟题大更新:4个组卷+11个专项,助力孩子更便捷、有效、有趣地备赛

自从《中文自修》杂志社昨天发通知,官宣了2023年第十届汉字小达人市级比赛的日期和安排后,各路学霸们闻风而动,在自己本就繁忙的日程中又加了一项:备赛汉字小达人市级比赛,11月30日,16点-18点。 根据这几年…

软磁直流测试系统全自动测量软件

软磁直流测试系统软件能够运行于 Windows 系统下作界面全中文提示,操作直观简捷。全自动控制与计算,智能化判断,最大限度消除人工操作所带来的误差。自动测量:Bm、Br、Hc、μi、μm 等静态磁特性参数;并绘制磁滞回线、…

记录:unity脚本的编写6.0

目录 unity UI系统添加ui编写脚本 unity UI系统 在日常的游戏或者别的什么活动中,ui总是必不可少的一项,在java中也有关于GUI的内容,unity也不例外,这次就使用脚本控制在unity添加的各种ui组件,使他们可以完成一些我们…

企业级真实应用利用Mybatis-Plus进行分页查询处理

怎么导入依赖我在之前的文章里边有说过不理解的可以看看 你应该懂点Mybatis-plus&#xff0c;真的好用 1&#xff1a;了解Page<T>类的使用 首先我们需要使用到Page类 &#xff0c;建立一个Page类&#xff0c;泛式类型中放入我们需要输出的类&#xff0c;是列表的话就…

(C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。

要求&#xff1a;原始数组的数据从键盘随机输入&#xff0c;新数组以4行4列的方式输出。 #include<stdio.h> int main() {int matrix[4][4],matrix2[4][4];int count;for(int i 0;i < 4;i )for(int j 0;j < 4;j )scanf("%d",&matrix[i][j]);for(i…

HarmonyOS元服务实现今天吃什么

一、前言 作为一个职业打工人&#xff0c;每天点外卖吃啥东西都有选择综合症&#xff0c;突发奇想让程序帮我们随机选择一个吃的&#xff0c;是不是可以解决我们的选择问题呢&#xff0c;说干就干&#xff0c;我们就使用HarmonyOS元服务实现一下这个功能。为什么选择这个Harmon…