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多表连接查询的执行细节
Apr 24 MySQL
解决MySQL存储时间出现不一致的问题
Apr 28 MySQL
Mysql基础知识点汇总
May 26 MySQL
MySQL中distinct和count(*)的使用方法比较
May 26 MySQL
MySQL GRANT用户授权的实现
Jun 18 MySQL
一次MySQL启动导致的事故实战记录
Sep 15 MySQL
mysql的Buffer Pool存储及原理
Apr 02 MySQL
排查并解决MySQL生产库内存使用率高的报警
Apr 11 MySQL
Mysql排查分析慢sql之explain实战案例
Apr 19 MySQL
解决Mysql中的innoDB幻读问题
Apr 29 MySQL
MySQL数据库Innodb 引擎实现mvcc锁
May 06 MySQL
MySQL如何修改字段类型和字段长度
Jun 10 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 服务器配置(使用Apache及IIS两种方法)
2009/06/01 PHP
PHP实现上传多文件示例代码
2017/02/20 PHP
利用ajax和PHP实现简单的流程管理
2017/03/23 PHP
PHP实现打包zip并下载功能
2018/06/12 PHP
PHP+MySQL实现在线测试答题实例
2020/01/02 PHP
jQuery中的bind绑定事件与文本框改变事件的临时解决方法
2010/08/13 Javascript
jQuery lazyload 的重复加载错误以及修复方法
2010/11/19 Javascript
JavaScript学习笔记(一) js基本语法
2011/10/25 Javascript
javascript 树形导航菜单实例代码
2013/08/13 Javascript
jQuery插件实现静态HTML验证码校验
2015/11/06 Javascript
一不小心就做错的JS闭包面试题
2015/11/25 Javascript
BootStrap智能表单实战系列(四)表单布局介绍
2016/06/13 Javascript
JS实现简单易用的手机端浮动窗口显示效果
2016/09/07 Javascript
利用Node.js+Koa框架实现前后端交互的方法
2017/02/27 Javascript
详解node HTTP请求客户端 - Request
2017/05/05 Javascript
Jquery把获取到的input值转换成json
2017/05/15 jQuery
React+react-dropzone+node.js实现图片上传的示例代码
2017/08/23 Javascript
vue基于mint-ui的城市选择3级联动的示例
2017/10/25 Javascript
AngularJS双向数据绑定原理之$watch、$apply和$digest的应用
2018/01/30 Javascript
vue-router命名视图的使用讲解
2019/01/19 Javascript
详解keep-alive + vuex 让缓存的页面灵活起来
2019/04/19 Javascript
前端Electron新手入门教程详解
2019/06/21 Javascript
node使用mysql获取数据库数据中文乱码问题的解决
2019/12/02 Javascript
Python3 能振兴 Python的原因分析
2014/11/28 Python
python装饰器深入学习
2018/04/06 Python
python 和c++实现旋转矩阵到欧拉角的变换方式
2019/12/04 Python
HTML页面中添加Canvas标签示例
2015/01/01 HTML / CSS
德国滑雪和户外用品网上商店:XSPO
2019/10/30 全球购物
俄罗斯童装网上商店:BebaKids
2020/06/06 全球购物
优秀毕业生自荐信范文
2014/01/01 职场文书
家长学校实施方案
2014/03/15 职场文书
超市周年庆活动方案
2014/08/16 职场文书
2014年银行年终工作总结
2014/12/19 职场文书
签订劳动合同通知书
2015/04/16 职场文书
田径运动会通讯稿
2015/07/18 职场文书
第四次工业革命,打工人与机器人的竞争
2022/04/21 数码科技