首页 > 数据库 >[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE

时间:2024-01-23 12:32:36浏览次数:49  
标签:... 事务 获取 数据共享 行级 索引 共享 数据 SELECT

一、译文

翻译来自官方文档:Locking Reads

If you query data and then insert or update related data within the same transaction, the regular SELECT statement does not give enough protection. Other transactions can update or delete the same rows you just queried. InnoDB supports two types of locking reads that offer extra safety:

如果你在查询数据,然后在同一个事务里插入或者修改相关的数据,常规的 select 语句不会提供足够的保护。其他的事务可以修改或者删除你正在查询的行。InnoDB 支持两种可以提供安全机制的读取锁:

SELECT … LOCK IN SHARE MODE sets a shared mode lock on any rows that are read. Other sessions can read the rows, but cannot modify them until your transaction commits. If any of these rows were changed by another transaction that has not yet committed, your query waits until that transaction ends and then uses the latest values.

SELECT … LOCK IN SHARE MODE 在读取的行上设置一个共享锁,其他的session可以读这些行,但在你的事务提交之前不可以修改它们。如果这些行里有被其他的还没有提交的事务修改,你的查询会等到那个事务结束之后使用最新的值。

For index records the search encounters, SELECT … FOR UPDATE locks the rows and any associated index entries, the same as if you issued an UPDATE statement for those rows. Other transactions are blocked from updating those rows, from doing SELECT … LOCK IN SHARE MODE, or from reading the data in certain transaction isolation levels. Consistent reads ignore any locks set on the records that exist in the read view. (Old versions of a record cannot be locked; they are reconstructed by applying undo logs on an in-memory copy of the record.)

索引搜索遇到的记录,SELECT … FOR UPDATE 会锁住行及任何关联的索引条目,和你对那些行执行 update 语句相同。其他的事务会被阻塞在对这些行执行 update 操作,获取共享锁,或从某些事务隔离级别读取数据等操作。一致性读(Consistent Nonlocking Reads)会忽略在读取视图上的记录的任何锁。(旧版本的记录不能被锁定;它们通过应用撤销日志在记录的内存副本上时被重建。)

All locks set by LOCK IN SHARE MODE and FOR UPDATE queries are released when the transaction is committed or rolled back.

Note 
Locking of rows for update using SELECT FOR UPDATE only applies when autocommit is disabled (either by beginning transaction with START TRANSACTION or by setting autocommit to 0. If autocommit is enabled, the rows matching the specification are not locked.

所有被共享锁和排他锁查询所设置的锁都会在事务提交或者回滚之后被释放。

注: 
使用 SELECT FOR UPDATE 为 update 操作锁定行,只适用于 autocommit 被禁用(当使用 START TRANSACTION 开始事务或者设置 autocommit 为0时)。如果 autocommit 已启用,符合规范的行不会被锁定。

二、总结

此处参考:MySQL中的共享锁与排他锁

SELECT … LOCK IN SHARE MODE :共享锁(S锁, share locks)。其他事务可以读取数据,但不能对该数据进行修改,直到所有的共享锁被释放。

如果事务对某行数据加上共享锁之后,可进行读写操作;其他事务可以对该数据加共享锁,但不能加排他锁,且只能读数据,不能修改数据。

SELECT … FOR UPDATE:排他锁(X锁, exclusive locks)。如果事务对数据加上排他锁之后,则其他事务不能对该数据加任何的锁。获取排他锁的事务既能读取数据,也能修改数据。

注:普通 select 语句默认不加锁,而CUD操作默认加排他锁。

三、验证

注:使用 mysql 版本为 5.7.9,事务隔离级别为InnoDB默认隔离级别 可重复读(Repeated Read)。

对以下几种情况进行验证:

  1. 当前事务获取共享锁后,可以读写,其他事务是否可以进行读写操作和获取共享锁;
  2. 两个事务同时获取共享锁后,是否可以进行update操作;
  3. 当前事务获取排他锁后,其他事务是否可以进行读写操作和获取共享锁;
  4. 是否可对一条数据加多个排他锁;
  5. 行锁和索引的关系;
  6. 索引数据重复率太高会导致全表扫描;

1、当前事务获取共享锁后,可以读写,其他事务是否可以进行读写操作和获取共享锁:可以读,可以获取共享锁,不可以写

当前事务可以写: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据共享

事务1获取某行数据共享锁后,事务2更新该行阻塞: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_共享锁_02

事务1提交之后,事务2更新成功: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据共享_03

2、两个事务同时获取某行数据共享锁后,是否可以进行update操作:不可以

两个事务同时获取某行数据共享锁,事务1更新该行阻塞: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_共享锁_04

事务2提交之后,事务1更新成功: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据_05

3、当前事务获取某行数据排他锁后,其他事务是否可以对该行数据进行读写操作和获取共享锁:其他事务可以读,不可以获取共享锁,不可以写

可以读该行数据: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_共享锁_06

不可以获取该行数据共享锁: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据共享_07

不可以更新该行数据: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_共享锁_08

4、是否可对一条数据加多个排他锁:不可以 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_共享锁_09

5、行锁和索引的关系:查询字段未加索引(主键索引、普通索引等)时,使用表锁

注:InnoDB行级锁基于索引实现。

未加索引时,两种行锁情况为(使用表锁): 
- 事务1获取某行数据共享锁,其他事务可以获取不同行数据的共享锁,不可以获取不同行数据的排他锁 
- 事务1获取某行数据排他锁,其他事务不可以获取不同行数据的共享锁、排他锁

加索引后,两种行锁为(使用行锁):

  • 事务1获取某行数据共享锁,其他事务可以获取不同行数据的排他锁
  • 事务1获取某行数据排他锁,其他事务可以获取不同行数据的共享锁、排他锁

未加索引表结构: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据_10

未加索引,事务1获取某行数据共享锁,事务2获取不同行数据共享锁成功: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据_11

未加索引,事务1获取某行数据共享锁,事务2更新不同行数据阻塞: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_共享锁_12

未加索引,事务1获取某行数据排他锁,事务2获取不同行数据共享锁阻塞: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据_13

未加索引,事务1获取某行数据排他锁,事务2获取不同行数据排他锁阻塞: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_共享锁_14

加索引后表结构: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据_15

加索引后,事务1获取某行数据共享锁,事务2更新不同行数据成功: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据共享_16

加索引后,事务1获取某行数据排他锁,事务2获取不同行数据共享锁成功: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据_17

加索引后,事务1获取某行数据排他锁,事务2获取不同行数据排他锁成功: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据_18

6、索引数据重复率太高会导致全表扫描:当表中索引字段数据重复率太高,则MySQL可能会忽略索引,进行全表扫描,此时使用表锁。可使用 force index 强制使用索引。

表结构:

CREATE TABLE `room` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL,
  `username` varchar(200) NOT NULL DEFAULT '',
  `state` varchar(255) NOT NULL DEFAULT '-1',
  `created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `index_uid` (`uid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

表数据: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_共享锁_19

获取 uid = ‘11’ 的数据的行锁并更新,但更新失败: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据共享_20

降低数据重复率,更新成功: 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据共享_21

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_数据_22

强制使用索引,更新成功:force index(index_uid) 

[MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE_共享锁_23

注:此处如果使用表锁,为何其他事务可以获取排他锁?

答:由于使用 force index ,而 InnoDB 行级锁基于索引实现,因此此处使用的是行锁。

四、InnoDB 行锁类型简介

参考:Mysql中那些锁机制之InnoDB

InnoDB行锁的三种类型:

  • Record Lock:对索引项加锁,锁定符合条件的行。其他事务不能修改和删除加锁项;
  • Gap Lock:对索引项之间的“间隙”加锁,锁定记录的范围,不包含索引项本身。其他事务不能再锁范围内插入数据;
  • Next-key Lock: 锁定索引项本身和索引范围,即Record Lock 和 Gap Lock 的结合。可解决幻读问题。



标签:...,事务,获取,数据共享,行级,索引,共享,数据,SELECT
From: https://blog.51cto.com/u_16532032/9377241

相关文章

  • Layui select实现赋值和主动触发选择时间,及radio实现可取消
    Layuiselect赋值,并主动触发选择事件//Layuiselect赋值,并主动触发选择事件//Input:selectId:ID选择器,selectFilter:lay-filter名称,value:需要的赋值,text:显示文本值functionsetSelect(selectId,selectFilter,value,text){//赋值$(selectId).find("option[va......
  • [SQLAlchemy] sqlAlchemy学习笔记(2): 在orm中使用select
    SELECT的作用select在sql中的作用是选中特定列并以表的形式返回,是必要的关键字;在sqlalchemy中,select()方法会返回一个Select对象,并根据这个对象引入其他方法,如where(),join(),order_by()等等fromsqlalchemyimportselectstmt=select(User).where(User.name==......
  • 数据库学习笔记(三)—— MySQL 之 SELECT(查询)篇
    查询单表查询select分组函数,分组后的字段from表名[where条件][groupby分组的字段][having分组后的筛选][orderby排序列表];排序SELECT字段名FROM表名ORDERBY字段名[ASC|DESC];ASC表示升序,DESC表示降序,而ORDERBY默认值为ASC。多字段排......
  • 报告正式发布!RTE 开发者是搞音视频的那波儿人么?以及大家关心的薪资、岗位、职业发展路
    前言: 哈喽各位RTE开发者社区的小伙伴,**《实时互动行业人才洞察2024》**已经正式发布。 RTE开发者是搞音视频的那波儿人么?RTEbuilder又是什么含义?RTE行业从业者的薪资范围和职业发展路径是什么样的? 关注公众号**「RTE开发者社区」,回复关键词「人才报告」**即可获......
  • select count(*) 引发的思考
    1、属性上添加注解:@JsonIgnoreimportcom.fasterxml.jackson.annotation.JsonIgnore;@JsonIgnore@ApiModelProperty("属性")privateLongsqlTotal;privateinttotal;针对Long类型,接口返回时,会转化为字符串,这样做是因为怕前端解析时出现精度问题......
  • node-sass 安装出错 Cannot download "https://github.com/sass/node-sass...
    Downloadingbinaryfromhttps://github.com/sass/node-sass/releases/download/v4.14.1/win32-x64-83_binding.nodeCannotdownload"https://github.com/sass/node-sass/releases/download/v4.14.1/win32-x64-83_binding.node": github网站大多时候都访问不到,下载 win32-x......
  • 解决 Ant TreeSelect(树选择)组件可以使用键盘选中 disabled(已禁用)项的问题
    最近在使用AntDesignVue(V3.2.20)的TreeSelect组件时发现一个问题:tree-data中部分数据的disabled属性设置为了true,选项是“禁用”状态,无法通过鼠标点击选中,但是可以通过键盘↑↓键切换选项,按下Enter键选中。一开始还以为是bug,后来通过查阅文档和测试发现,该组件还......
  • vue2中使用v-selectpage插件 搜索并分页
    <v-selectpagedata="/api/intrusionevent/lists"v-model="temp.event_id"key-field="id"show-field="description"search-field="de......
  • CentOS7 报错 ”Repository base is listed more than once in the configuration...
    CentOS7在使用yum时出现以下错误:RepositorybaseislistedmorethanonceintheconfigurationRepositoryupdatesislistedmorethanonceintheconfigurationRepositoryextrasislistedmorethanonceintheconfigurationRepositorycentosplusislistedmore......
  • SqlSugar的Select用法
    Select位置正常情况:应该在最后面,一般是.Where(..).OrderBy(..).Select(..).ToList()特殊情况:如果Select不是最后一个位置,则Select要加MergeTable()合并成一个表,Select(...).MergeTable().Where语法糖:Select(...).MergeTable()在新版本中可以用SelectMergeTable(it=>newx......