一文学习MySQL 意向共享锁、意向排他锁、死锁
作者:BugMaker-shen 发布时间:2024-01-21 23:17:27
一、InnoDB表级锁
我们知道,InnoDB是支持行锁,但不是每次都获取行锁,如果不使用索引的,那还是获取的表锁。而且有的时候,我们希望直接去使用表锁
在绝大部分情况下都应该使用行锁,因为事务的并发效率比表锁更高,但个别情况下也使用表级锁:
事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,给大部分行都加锁(此时不如直接加表锁),不仅这个事务执行效率低,而且可能造成其他事务长时间等待和锁冲突
事务涉及多个表,比较复杂,如果都用行锁,很可能引起死锁,造成大量事务回滚
当我们希望获取表锁时,可以使用以下命令:
LOCK TABLE user READ -- 获取这张表的读锁
LOCK TABLE user WRITE -- 获取这张表的写锁
事务执行…
COMMIT/ROLLBACK; -- 事务提交或者回滚
UNLOCK TABLES; -- 本身自带提交事务,释放线程占用的所有表锁
在使用表锁的时候,涉及到效率的问题:
如果我们要获取一张表的排它锁X,最起码得确定,这张表没有被其他事务获取过S锁或X锁,以及这张表没有任何行被其他事务获取过行S或X锁
假如这张表有1000万个数据,那我怎么知道这1000万行哪些有行锁哪些没有行锁呢?
除了挨个检查,没有更好的办法,这就导致效率低下的问题
我们这里学习的意向共享锁和意向排他锁就是用来解决,由于需要加表锁而去挨个遍历数据,确定是否有某些数据被加了行锁,而导致的效率低下问题
二、意向共享锁和意向排他锁
为了可以更快速的获取表锁
意向共享锁(IS锁):事务计划给记录加行共享锁,事务在给一行记录加共享锁前,必须先取得该表的IS锁
意向排他锁(IX锁):事务计划给记录加行排他锁,事务在给一行记录加排他锁前,必须先取得该表的IX锁
在加行锁之前,由InnoDB存储引擎加上表的IS或IX锁
意向锁之间都兼容,不会产生冲突
意向锁存在的意义是为了更高效的获取表锁(表格中的X、S、IX、IS指的是表锁,不是行锁)
意向锁是表级锁,协调表锁和行锁的共存关系,主要目的是显示事务正在锁定某行或者试图锁定某行。
分析事务1获取行X锁和事务2获取表S锁:
首先事务1需要给表的第10行数据加X锁,于是InnoDB存储引擎自动给整张表加上了IX锁。当事务2再想获取整张表的S锁时,看到这张表已经有别的事务获取了IX锁了,就说明这张表肯定有某些数据被加上了X锁,这就导致事务2不能给整张表加S锁了。此时事务2只能等待,无法成功获取表S锁
三、死锁
1. 数据库中的死锁
MyISAM 表锁是 deadlock free 的, 这是因为 MyISAM 不支持事务,只支持表锁,而且总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。如果是处理多张表,还是可能出现死锁问题的
在 InnoDB 中,除单个 SQL 组成的事务外,锁是逐步获得的,即锁的粒度比较小(行锁),这就决定了在 InnoDB 中发生死锁是可能的
死锁问题一般都是我们自己的应用造成的,和多线程编程的死锁情况相似,大部分都是由于我们多个线程在获取多个锁资源的时候,获取的顺序不同而导致的死锁问题。因此我们应用在对数据库的多个表做更新的时候,不同的代码段,应对这些表按相同的顺序进行更新操作,以防止锁冲突导致死锁问题
2. 死锁场景以及解决办法
死锁出现的场景如下:
事务1成功获取行锁1
事务2成功获取行锁2
…
事务1无法获取行锁2,被阻塞的同时也无法释放行锁1
事务2无法获取行锁1,被阻塞的同时也无法释放行锁2
此时所有的事务都阻塞住了,相当于进程内的所有线程都阻塞住了,发生了死锁问题
解决死锁办法:多个事务/线程获取多个相同资源锁的时候应该按照同样的顺序获取锁。与此同时,由于mysqld(MySQL Server守护进程)设置了事务阻塞的超时时间,事务不会阻塞很长时间,超时后事务处理失败,自动释放当前占有的锁
3. 操作
设置自动提交 以及 可重复读隔离级别,开启事务
查询一下表数据,在可重复读隔离级别使用的是MVCC提供的快照读,并没有加锁
事务1获取id=7的排他锁,事务2获取id=8的排他锁
事务1再次获取id=8的排他锁,发生阻塞
事务2再次获取id=7的排他锁
此时由于MySQL Server检测到发生了死锁,于是解除事务1的阻塞,进行事务1的rollback,释放其占有的行锁,于是事务2成功获取id=7的排他锁
四、锁的优化建议
在能正确完成业务的前提下,为确保效率,尽量使用较低的隔离级别(必须避免脏读)
设计合理的索引并尽量使用索引访问数据,使加锁更准确,减少锁冲突的机会,提高并发能力
选择合理的事务大小,小事务发生锁冲突的概率小(事务越大,包含的SQL越多,可能包含更多的表资源和行资源的锁,增大了锁冲突的概率)
不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大大减少死锁的机会
尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响(其实等值查询也会加间隙锁)
不要申请超过实际需要的锁级别
除非必须,查询时不要显示加锁(在已提交读和可重复读隔离级别,MVCC提供了读取机制,不需要手动加锁)
来源:https://blog.csdn.net/qq_42500831/article/details/123751272


猜你喜欢
- Array.prototype._ = function(){var _p = 0;var _v = 0;(function(){ 
- 今天,本文向大家推荐20佳国外的脚本下载网站。1- Hot Scripts2- Code Canyon3- User Scripts4- S
- 对数据库的管理常规就是进行预防性的维护,以及修复那些出现问题的内容。进行检查和修复通常具有四个主要的任务:1. 对表进行优化2. 对表进行分
- 前言本文主要基于在Uber的Go monorepo中发现的各种数据竞争模式,分析了其背后的原因与分类,希望能够帮助更多的Go开发人员,去关注
- 这篇文章主要介绍了Python箱型图绘制与特征值获取过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 可以使用 Application 对象在给定的应用程序的所有用户之间共享信息。基于 ASP 的应用程序同所有的 .asp 文件一样在一个虚拟
- 上一章实现了登录的部分功能,之所以说是部分功能,是因为用户名和密码写成固定值肯定是不可以的,一个整体的功能,至少需要注册,登录,密码修改等,
- 在使用selenium webdriver进行元素定位时,通常使用findElement或findElements方法结合By类返回的元素句
- 1. 原因(1)js代码是运行在内存中的,代码运行时的所有变量、函数都是保存在内存中。(2)刷新页面,以前申请的内存被释放,重新加载脚本代码
- 前言首先抛出几个问题:console.log(Boolean({}));console.log(Number([]));console.lo
- 用Python打开Excel数据,读取时需要将”学号“和“ID"转换成
- 本教程旨在介绍如何使用七牛的Python SDK来快速地进行文件上传,下载,处理,管理等工作。安装首先,要使用Python的SDK必须要先安
- 在python中,总的来说有三种大的模式打开文件,分别是:a, w, r当以a模式打开时,只能写文件,而且是在文件末尾添加内容。当以a+模式
- 上次在“给网页添加打印按钮”一文中,有一段代码是“复制本文链接到剪贴板”js脚本,很可惜只能在IE中使用。这次在“淘宝网在线充值中心 - 荆
- 前言:由程序去执行的操作不允许有任何误差,有些时候在测试的时候未出现问题,但是放到服务器上就会报错,而且打印的错误信息并不十分明确。这时,我
- Python批量识别图片指定区域文字内容,供大家参考,具体内容如下简介对于一张图片,需求识别指定区域的内容1.截取原始图上的指定图片当做模板
- 摘要:现代网站和web应用程序趋向于依赖客户端的大量的javascript来提供丰富的交互。特别是通过不刷新页面的异步请求来返回数据或从服务
- 1、弹出菜单也叫上下文菜单,建立菜单并向菜单添加各种功能。2、右键监听鼠标。如右键点击,则根据位置判断弹出。3、调用Menupop方法。4、
- 执行数据库更新update操作的时候数据库卡死了问题分析一般都是数据库事务未提交,导致update或者delete卡死。解决办法在执行完更新
- MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQLAB公司,在2008年1月16号被Sun公司收购。MySQL被广泛地应用在I