当前位置: 首页 > news >正文

【MySQL中的锁】

MySQL中的锁

          • [1] 为什么要加锁
          • [2] 不同引擎所支持的锁?
          • [3] 行锁:悲观锁
          • [4] 意向锁
          • [5] 间隙锁
          • [5] MVCC:乐观锁
          • [6] 什么时候会加锁?

原文链接:https://blog.csdn.net/soonfly/article/details/70238902

首先从思想上无论在java还是mysql都有这乐观锁和悲观锁的概念,数据库可以分为悲观锁(共享锁和排他锁),本文就从这里入手

[1] 为什么要加锁

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的 计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一 个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。本章我们着重讨论MySQL锁机制 的特点,常见的锁问题,以及解决MySQL锁问题的一些方法或建议。

[2] 不同引擎所支持的锁?

它们都支持表级锁,BDB采用页面锁,InnoDB采用的是行级锁。

MyISAM和MEMORY存储引擎:采用的是表级锁(table-level locking);

BDB存储引擎:采用的是页面锁(page-level locking),但也支持表级锁;

InnoDB存储引擎:既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
从上述特点可见,很难笼统地说哪种锁更好,只能就具体应用的特点来说哪种锁更合适!仅从锁的角度 来说:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有 并发查询的应用,如一些在线事务处理(OLTP)系统。

MySQL的表级锁有两种模式**:表共享读锁(Table Read Lock)表独占写锁(Table Write Lock)**。

[3] 行锁:悲观锁

InnoDB实现了以下两种类型的悲观锁

  • X锁(Exclusive Lock)—排他锁或独占锁:若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁.它防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止.在更新操作(INSERT、UPDATE 或 DELETE)过程中始终应用排它锁.

    注意:排他锁会阻止其它事务再对其锁定的数据加读或写的锁,但是不加锁的就没办法控制了.

排他锁指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁,而并非不能读

在select命令中使用独占锁的SQL语句为:select … for update;

  • S锁(Shared Lock)—共享锁:若事务T对数据对象A加上S锁,则事务T只能读A;其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁.这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改.

如果在select查询语句中要手动加入共享锁,那么对应的SQL语句为:select … lock in share mode

InnoDB行锁实现方式
InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!

[4] 意向锁

为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。

意向共享锁(IS):事务打算给数据行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
这里写图片描述

如果一个事务请求的锁模式与当前的锁兼容,InnoDB就请求的锁授予该事务;反之,如果两者两者不兼容,该事务就要等待锁释放。
意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁。
事务可以通过以下语句显式给记录集加共享锁或排他锁

共享锁(S):SELECT * FROM table_name WHERE … LOCK IN SHARE MODE。
排他锁(X):SELECT * FROM table_name WHERE … FOR UPDATE。
用SELECT … IN SHARE MODE获得共享锁,主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT… FOR UPDATE方式获得排他锁。

[5] 间隙锁

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁 (Next-Key锁)。
举例来说,假如emp表中只有101条记录,其empid的值分别是 1,2,…,100,101,下面的SQL:

Select * from  emp where empid > 100 for update;

是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁。

InnoDB使用间隙锁的目的,一方面是为了防止幻读,以满足相关隔离级别的要求,对于上面的例子,要是不使 用间隙锁,如果其他事务插入了empid大于100的任何记录,那么本事务如果再次执行上述语句,就会发生幻读;另外一方面,是为了满足其恢复和复制的需 要。有关其恢复和复制对锁机制的影响,以及不同隔离级别下InnoDB使用间隙锁的情况,在后续的章节中会做进一步介绍。

很显然,在使用范围条件检索并锁定记录时,InnoDB这种加锁机制会阻塞符合条件范围内键值的并发插入,这往往会造成严重的锁等待。因此,在实际应用开发中,尤其是并发插入比较多的应用,我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。

在mysql的innoDB存储引擎中,如果更新操作是针对一个区间的,那么它会锁住这个区间内所有的记录,比如update xxx where id between a and b那么它会锁住a到b之间所有记录,注意是所有记录,甚至这个记录并不存在也会被锁住,这个时候,如果另外一个连接需要插入一条记录到a到b之间,那么它就必须等到上一个事务结束。

[5] MVCC:乐观锁

https://www.jianshu.com/p/56fa361e0d94

mysql的innodb采用的是行锁,而且采用了多版本并发控制来提高读操作的性能。 什么是多版本并发控制呢 ?

MVCC:multiversion concurrency control其实就是在每一行记录的后面增加两个隐藏列,记录创建版本号和删除版本号。 而每一个事务在启动的时候,都有一个唯一的递增的版本号

1、在插入操作时记录的创建版本号就是事务版本号。比如我插入一条记录, 事务id 假设是1 ,那么记录如下:

idnamecreate versiondelete version
1test1

2、在更新操作的时候,采用的是先标记旧的那行记录为已删除,并且删除版本号是事务版本号,然后插入一行新的记录的方式。比如,针对上面那行记录,事务Id为2 要把name字段更新

update table set name= 'new_value' where id=1;
idnamecreate versiondelete version
1test12
1new_value2

3、删除操作的时候,就把事务版本号作为删除版本号。比如

delete from table where id=1;
idnamecreate versiondelete version
1new_value23

4、查询操作
从上面的描述可以看到,在查询时要符合以下两个条件的记录才能被事务查询出来:

  1. 删除版本号 大于 当前事务版本号,就是说删除操作是在当前事务启动之后做的
  2. 创建版本号 小于或者等于 当前事务版本号 ,就是说记录创建是在事务中(等于的情况)或者事务启动之前

创建版本号<=当前事务版本号<删除版本号

  1. 这样就保证了各个事务互不影响。从这里也可以体会到一种提高系统性能的思路,就是: 通过版本号来减少锁的争用。
  2. 另外,只有read-committed和 repeatable-read 两种事务隔离级别才能使用MVCC
    read-uncommited由于是读到未提交的,所以不存在版本的问题
  3. 而serializable 则会对所有读取的行加锁。
[6] 什么时候会加锁?

在数据库增删改查四种操作中**,insert、delete和update都是会加排它锁**(Exclusive Locks)的,select不会加锁,只有显式声明才会加锁:

  • select: 即最常用的查询,是不加任何锁的
  • select … lock in share mode: 会加共享锁(Shared Locks)
  • select … for update: 会加排它锁

相关文章:

  • Linux在线安装git(亲测成功)
  • [<MySQL优化总结>]
  • yum update
  • Redis是什么?
  • C语言中函数返回值的问题
  • 哈夫曼树
  • Redis有哪五种不同类型的值?应用场景有哪些?
  • jvm重要参数分析
  • 使用redis可能出现的问题
  • phpQuery对数据信息的采集进一步学习
  • Redis底层数据结构
  • 用户口令复杂度策略设置银河麒麟
  • Redis的过期策略
  • 第三周作业 产品同质化问题
  • Redis分布式锁
  • 「面试题」如何实现一个圣杯布局?
  • Angular 4.x 动态创建组件
  • CentOS7简单部署NFS
  • java8-模拟hadoop
  • JavaScript的使用你知道几种?(上)
  • JavaScript服务器推送技术之 WebSocket
  • Linux Process Manage
  • linux学习笔记
  • nfs客户端进程变D,延伸linux的lock
  • Puppeteer:浏览器控制器
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • 产品三维模型在线预览
  • 第2章 网络文档
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 记录一下第一次使用npm
  • 离散点最小(凸)包围边界查找
  • 使用SAX解析XML
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 微信开源mars源码分析1—上层samples分析
  • 运行时添加log4j2的appender
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • 如何正确理解,内页权重高于首页?
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • # 计算机视觉入门
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #mysql 8.0 踩坑日记
  • (1) caustics\
  • (16)Reactor的测试——响应式Spring的道法术器
  • (2)Java 简介
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (独孤九剑)--文件系统