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 相关文章推荐
left join、inner join、right join的区别
Apr 05 MySQL
详解Mysql 函数调用优化
Apr 07 MySQL
MySQL 角色(role)功能介绍
Apr 24 MySQL
低版本Druid连接池+MySQL驱动8.0导致线程阻塞、性能受限
Jul 01 MySQL
VS2019连接MySQL数据库的过程及常见问题总结
Nov 27 MySQL
MySQL图形化管理工具Navicat安装步骤
Dec 04 MySQL
面试提问mysql一张表到底能存多少数据
Mar 13 MySQL
mysql查询结果实现多列拼接查询
Apr 03 MySQL
MySQL创建管理子分区
Apr 13 MySQL
MySQL 逻辑备份 into outfile
May 15 MySQL
MySQL8.0 Undo Tablespace管理详解
Jun 16 MySQL
delete in子查询不走索引问题分析
Jul 07 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
echo, print, printf 和 sprintf 区别
2006/12/06 PHP
比较全面的PHP数组的使用方法小结
2010/09/23 PHP
PHP和Mysqlweb应用开发核心技术-第1部分 Php基础-2 php语言介绍
2011/07/03 PHP
学习php设计模式 php实现建造者模式
2015/12/07 PHP
PHP弱类型的安全问题详细总结
2016/09/25 PHP
简单实现PHP留言板功能
2016/12/21 PHP
tp5.1 框架路由操作-URL生成实例分析
2020/05/26 PHP
基于JQuery的数字改变的动画效果--可用来做计数器
2010/08/11 Javascript
js移除事件 js绑定事件实例应用
2012/11/28 Javascript
javascript删除option选项的多种方法总结
2013/11/22 Javascript
js对象内部访问this修饰的成员函数示例
2014/04/27 Javascript
JS实现很酷的水波文字特效实例
2015/02/26 Javascript
利用Angularjs和bootstrap实现购物车功能
2016/08/31 Javascript
浅谈js中StringBuffer类的实现方法及使用
2016/09/02 Javascript
JS命令模式例子之菜单程序
2016/10/10 Javascript
jquery.validate[.unobtrusive]和Bootstrap实现tooltip错误提示问题分析
2016/10/30 Javascript
js css3实现图片拖拽效果
2017/03/04 Javascript
MUI  Scroll插件的使用详解
2017/04/13 Javascript
取消Bootstrap的dropdown-menu点击默认关闭事件方法
2018/08/10 Javascript
解决vuecli3.0热更新失效的问题
2018/09/19 Javascript
layer实现弹出层自动调节位置
2019/09/05 Javascript
Vue插件之滑动验证码
2019/09/21 Javascript
基于leaflet.js实现修改地图主题样式的流程分析
2020/05/15 Javascript
JS实现图片幻灯片效果代码实例
2020/05/21 Javascript
python中的hashlib和base64加密模块使用实例
2014/09/02 Python
Python常用的json标准库
2019/02/19 Python
PyQt5基本控件使用之消息弹出、用户输入、文件对话框的使用方法
2019/08/06 Python
python的sys.path模块路径添加方式
2020/03/09 Python
网站性能延迟加载图像的五种技巧(小结)
2020/08/13 HTML / CSS
高中毕业生生活的自我评价
2013/12/08 职场文书
篝火晚会主持词
2014/03/25 职场文书
公司感恩节活动策划书
2014/10/11 职场文书
试用期工作表现自我评价
2015/03/06 职场文书
公司行政助理岗位职责
2015/04/11 职场文书
校园开放日新闻稿
2015/07/17 职场文书
详解JAVA中的OPTIONAL
2021/06/14 Java/Android