MySQL锁机制


Posted in MySQL onApril 05, 2021

锁是计算机协调多个线程访问同一共享资源的机制,主要用于解决多线程访问同一共享资源的并发安全问题。
MySQL锁机制

锁分类

(1)从性能分为:乐观锁和悲观锁
MySQL中采用版本号控制,JVM中使用CAS

(2)从数据库操作类型分为:读锁(共享锁)、写锁(排他锁) 【读锁和写锁都属于悲观锁】

  • 读锁(共享锁):针对相同行记录,多个读操作可以同时进行,但任何事务都不能进行
  • 写锁(排他锁):获取排他锁的事务既能读数据,又能修改数据。获取到写锁的事务为完成之前,会阻塞其他事务获取写锁或读锁。

(3)从颗粒度划分为,表锁和行锁

注意:
(1)读锁、写锁都属于行级锁,即事务1 对商品A 获取写锁,和事务2对商品B 获取写锁互相不会阻塞的。
(2)如果sql语句使用了行锁,当SQL未使用索引而使用全表扫描的时候,行级锁会变成表锁。

(3)锁只有在执行commit或者rollback的时候才会释放,并且所有的锁都是在同一时刻被释放。
(4)Innodb引擎执行普通的修改、删除sql语句时,会给修改和删除的行加行锁。

共享锁(读锁,读写互斥,读读互不影响)

事务A使用共享锁获取了某条(或某些)记录时,事务B可以读取这些记录,可以继续添加共享锁,但是不能修改这些记录(当事务C对这些数据修改或删除时,会进入阻塞状态,直至锁等待超时或者事务A提交)

  • 如何使用共享锁和释放共享锁
# 加锁
SELECT ... LOCK IN SHARE MODE
# 释放锁
commit;
rollback;
  • 作用
    SELECT … LOCK IN SHARE MODE在读取的若干行记录加共享锁(share lock),其他事务只能对这些行查询而不能修改这些记录。多个事务可以对相同的行记录加共享锁,因此获取了共享锁的事务不一定能修改行数据

  • 使用场景: 读取结果集的最新版本,同时防止其他事务产生更新该结果集
    例如:并发下对商品库存的操作

排他锁(写锁,独占锁)

select … for update在对读取的行记录加排他锁,只允许获取到该排他锁的事务修改该行记录,防止其他事务对该行进行修改,就像普通的update语句执行时会加行锁一样。

  • 如何使用排他锁
# 加排他锁
select ... for update //排他锁 

# 释放锁
commit;
rollback;

共享锁和排他锁的区别

(1)一旦某个事务获取了排他锁,其他事务就无法再获取排他锁。
多个事务可以对相同行数据加共享锁。
(2)给指定行加了共享锁的事务,不一定能修改该行数据,因为其他事务也可能对该行加了共享锁或排他锁; 给指定行加了排他锁的事务,则可以修改加了排他锁的该行数据

表锁

使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。
表锁一般在数据迁移时使用。

意向锁:意向共享锁和意向排他锁

某行加共享锁的前提是:该行数据所在表会先获取到意向共享锁。
某行加排他锁的前提是:该行数据所在表会先获取到意向排他锁。
注意:意向共享锁和意向排他锁均是表锁,无法手动创建。

为什么需要加入意向锁

意向锁是为了告知mysql该表已经存在数据被加锁,而不需要逐行扫描是否加锁,提搞加锁的效率。

单个表锁定

lock tables saas.goods read,saas.account write;  // 给saas库中的goods表加读锁,account表加写锁
unlock tables;   //解锁

全局表锁定

FLUSH TABLES WITH READ LOCK;   // 所有库所有表都被锁定只读
unlock tables;         //解锁

注意: 在客户端和数据库断开连接时,都会隐式的执行unlock tables。如果要让表锁定生效就必须一直保持连接。

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
    行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;

行锁

  • 行锁是锁一行或者多行记录
  • MySQL的行锁是基于索引,行锁是加在索引上,而不是加在行记录上的。
    MySQL锁机制
    如上图所示,数据库中有1个主键索引和1个普通索引,图中的sql语句是基于普通索引查询,命中4条记录,此时一把行锁就锁定两条记录,而其他事务修改这两条记录中的任意一条,都会一直阻塞【获取锁的事务没有执行commit之前】,下图就是上图没有执行commit语句时的情况。
    MySQL锁机制

行锁升级为表锁(行锁实际是给索引加锁,如果没用索引而全表扫描,则会给全表加锁)

MySQL锁机制
上图中where条件中,虽然template_name建立普通索引,但使用or关键字,导致template_name的索引失效,从而进行了全表扫描,锁定了整张表。

修改、删除某一行记录,且未提交事务时,该行会一直被行锁锁定

MySQL锁机制
窗口1中删除某一行,但没有提交。窗口2中更新该行会一直处于阻塞中。
MySQL锁机制

记录锁

  • 行锁:行锁是命中索引,一把锁锁的是一张表的一条记录或多条记录
  • 记录锁:记录锁是在行锁的衍生锁,记录锁锁的是表中的某一条记录,记录锁出现的条件必须是:精确命中索引,且索引是唯一索引(比如主键id、唯一索引列)。

间隙锁(Gap Locks)

经典参考文章

间隙锁的作用:防止幻读

间隙锁的目的是为了防止幻读,其主要通过两个方面实现这个目的:
(1)防止止间隙内有新数据被插入
(2)防止范围内已存在的数据被更新

innodb自动使用间隙锁的条件

(1)数据隔离级别必须为可重复读
(2)检索条件必须使用索引(没有使用索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加)

间隙锁锁定的区域

根据检索条件向左寻找最靠近检索条件的记录值A,作为左区间,向右寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B)。下图中,where number=5的话,那么间隙锁的区间范围为[4,11];
MySQL锁机制

session 1:
start  transaction ;
触发间隙锁的方式1:
select  * from news where number=4 for update ;
触发间隙锁的方式2:
update news set number=3 where number=4; 

session 2:
start  transaction ;
insert into news value(2,4);#(阻塞)
insert into news value(2,2);#(阻塞)
insert into news value(4,4);#(阻塞)
insert into news value(4,5);#(阻塞)
insert into news value(7,5);#(执行成功)
insert into news value(9,5);#(执行成功)
insert into news value(11,5);#(执行成功)

next-key锁【临键锁】

next-key锁其实包含了记录锁和间隙锁,即锁定一个范围,并且锁定记录本身。InnoDB默认加锁方式是next-key 锁。

select * from news where number=4 for update ;

MySQL锁机制

next-key锁锁定的范围为间隙锁+记录锁,即区间(2,4),(4,5)加间隙锁,同时number=4的记录加记录锁,即next-key锁的锁定的范围为(2,4],(4,5]。

记录锁、间隙锁、临间锁的区别

MySQL锁机制

update news  set number=0 where id>15

sql默认加的是next-key锁。根据上图,next-key锁的区间为(-∞,1],(1,5],(5,9],(9,11],(11,+∞),上面id>15,实际上next-key锁是加在[11,+∞)这个范围内,而不是(15,+∞)这个范围内。注意:需要使用锁的字段必须加索引,因为锁是加在索引上的,没有索引则加的表锁。

MySQL 相关文章推荐
Mysql 用户权限管理实现
May 25 MySQL
Mysql数据库索引面试题(程序员基础技能)
May 31 MySQL
安装配置mysql及Navicat prenium的详细流程
Jun 10 MySQL
MySQL七种JOIN类型小结
Oct 24 MySQL
关于MySQL中的 like操作符详情
Nov 17 MySQL
浅谈mysql哪些情况会导致索引失效
Nov 20 MySQL
优化Mysql查询的示例
Apr 26 MySQL
MySql数据库 查询时间序列间隔
May 11 MySQL
MySQL普通表如何转换成分区表
May 30 MySQL
sql注入报错之注入原理实例解析
Jun 10 MySQL
MySQL数据库实验之 触发器和存储过程
Jun 21 MySQL
mysql sock文件存储了什么信息
Jul 15 MySQL
MySQL基础(一)
Apr 05 #MySQL
MySQL基础(二)
MySQL学习总结-基础架构概述
MySQL令人咋舌的隐式转换
Apr 05 #MySQL
mysql知识点整理
Apr 05 #MySQL
浅析InnoDB索引结构
Apr 05 #MySQL
MySQL入门命令之函数-单行函数-流程控制函数
Apr 05 #MySQL
You might like
一个自定义位数的php多用户计数器代码
2007/03/11 PHP
PHP中如何判断AJAX提交的数据
2012/02/05 PHP
在php和MySql中计算时间差的方法详解
2015/03/27 PHP
PHP实现原比例生成缩略图的方法
2016/02/03 PHP
使用PHP反射机制来构造"CREATE TABLE"的sql语句
2019/03/21 PHP
thinkPHP5使用Rabc实现权限管理
2019/08/28 PHP
jQuery动画特效实例教程
2014/08/29 Javascript
JavaScript制作简易的微信打飞机
2015/03/31 Javascript
实现无刷新联动例子汇总
2015/05/20 Javascript
Bootstrap实现input控件失去焦点时验证
2016/08/04 Javascript
Angular ng-repeat遍历渲染完页面后执行其他操作详细介绍
2016/12/13 Javascript
canvas 绘制圆形时钟
2017/02/22 Javascript
Nodejs 复制文件/文件夹的方法
2017/08/24 NodeJs
Windows下Node.js安装及环境配置方法
2017/09/18 Javascript
如何选择适合你的JavaScript框架
2017/11/20 Javascript
JS从非数组对象转数组的方法小结
2018/03/26 Javascript
详解如何使用koa实现socket.io官网的例子
2018/11/04 Javascript
微信小程序自定义可滑动顶部TabBar选项卡实现页面切换功能示例
2019/05/14 Javascript
vue history 模式打包部署在域名的二级目录的配置指南
2019/07/02 Javascript
在Uni中使用Vue的EventBus总线机制操作
2020/07/31 Javascript
[06:16]DOTA2守卫传承者——职业选手谈心路历程
2015/02/26 DOTA
深入解析Python的Tornado框架中内置的模板引擎
2016/07/11 Python
Python基于TCP实现会聊天的小机器人功能示例
2018/04/09 Python
对python读取CT医学图像的实例详解
2019/01/24 Python
css3 给背景设置渐变色的方法
2019/09/12 HTML / CSS
匡威英国官网:Converse英国
2018/12/02 全球购物
英国Iceland杂货店:网上食品购物
2020/12/16 全球购物
什么是虚拟内存?虚拟内存有什么优势?
2012/02/19 面试题
医药个人求职信范文
2014/01/29 职场文书
经贸专业毕业生求职信
2014/03/23 职场文书
个人三严三实对照检查材料思想汇报
2014/09/22 职场文书
工作收入住址证明
2014/10/28 职场文书
实习介绍信范文
2015/05/05 职场文书
观看禁毒宣传片后的感想
2015/08/11 职场文书
旅行社计调工作总结
2015/08/12 职场文书
javascript代码简写的几种常用方式汇总
2021/08/23 Javascript