select...for update 锁表了?

news2024/9/21 19:04:06

在MySQL中,事务A中使用select...for update where id=1锁住了,某一条数据,事务还没提交,此时,事务B中去用select ... where id=1查询那条数据,会阻塞等待吗?

select...for update在MySQL中,是一种悲观锁的用法,一般情况下,会锁住一行数据,但如果没有使用正确的话,也会把整张表锁住。

其实,我之前也在实际项目中试过用,比如:积分兑换礼品的功能。

今天跟大家一起聊聊select...for update这个话题,希望对你会有所帮助。

1. 为什么要用行锁?

假如现在有这样一种业务场景:用户A给你转账了2000元,用户B给你转账了3000元,而你的账户初始化金额是1000元。

在事务1中会执行下面这条sql:

update account set money=money+2000 
where id=123;

在事务2中执行下面这条sql:

update account set money=money+3000 
where id=123;

这两条sql执行成功之后,你的money可能是:3000、4000、6000,这三种情况中的一种。

你之前的想法是,用户A和用户B总共给你转账5000,最终你账户的钱应该是6000才对,3000和4000是怎么来的?

假如事务1在执行update语句的过程中,事务2同时也在执行update语句。

事务1中查询到money是1000,此外事务2也查询到money是1000。

如果事务1先执行update语句,事务2后执行update语句,第一次update的3000,会被后面的4000覆盖掉,最终结果为4000。

如果事务2先执行update语句,事务1后执行update语句,第一次update的4000,会被后面的3000覆盖掉,最终结果为3000。

这两种情况都产生了严重的数据问题。

我们需要有某种机制,保证事务1和事务2要顺序执行,不要一起执行。

这就需要加锁了。

目前MySQL中使用比较多的有:表锁、行锁和间隙锁。

我们这个业务场景,非常时候使用行锁

在事务1执行update语句的过程中,先要把某一行数据锁住,此时,其他的事务必须等待事务1执行完,提交了事务,才能获取那一行的数据。

在MySQL中是通过select...for update语句来实现的行锁的功能。

但如果你在实际工作中使用不正确,也容易把整张表锁住,严重影响性能。

select...where...for update语句的用法是否正确,跟where条件中的参数有很大的关系。

我们一起看看下面几种情况。

假如user表现在有这样的数据库,数据库的版本是:8.0.21,数据库的隔离级别是:REPEATABLE-READ。

 

创建的索引如下: 

其中id是主键字段,code是唯一索引字段,name是普通索引字段,其他的都是普通字段。

 

2. 主键

当where条件用的数据库主键时。

例如开启一个事务1,在事务中更新id=1的用户的年龄:

begin;
select * from user where id=1 for update;
update user set age=22 where id=1;

where条件中的id是数据库的主键,并且使用for update关键字,加了一个行锁,这个事务没有commit。

此时,开启了另外一个事务2,也更新id=1的用户的年龄:

begin;
update user set age=23 where id=1;
commit;

在执行事务2的sql语句的过程中,会一直等待事务1释放锁。

 如果事务1一直都不释放行锁,事务2最后会报下面这个异常:

 

如果此时开始一个事务3,更新id=2的用户的年龄:

begin;
update user set age=23 where id=2;
commit;

 执行结果如下:

 

由于事务3中更新的另外一行数据,因此可以执行成功。

说明使用for update关键字,锁住了主键id=1的那一行数据,对其他行的数据并没有影响。

 

3. 唯一索引

当where条件用的数据库唯一索引时。

开启一个事务1,在事务中更新code=101的用户的年龄:

begin;
select * from user where code='101' for update;
update user set age=22 where code='101';

where条件中的code是数据库的唯一索引,并且使用for update关键字,加了一个行锁,这个事务没有commit。

此时,开启了另外一个事务2,也更新code=101的用户的年龄:

begin;
update user set age=23 where code='101';
commit;

执行结果跟主键的情况是一样的。 

 

4. 普通索引

当where条件用的数据库普通索引时。

开启一个事务1,在事务中更新name=周星驰的用户的年龄:

begin;
select * from user where name='周星驰' for update;
update user set age=22 where name='周星驰';

where条件中的name是数据库的普通索引,并且使用for update关键字,加了一个行锁,这个事务没有commit。

此时,开启了另外一个事务2,也更新name=周星驰的用户的年龄:

begin;
update user set age=23 where name='周星驰';
commit;

 执行结果跟主键的情况也是一样的。

 

5. 主键范围

当where条件用的数据库主键范围时。

开启一个事务1,在事务中更新id in (1,2)的用户的年龄:

begin;
select * from user where id in (1,2) for update;
update user set age=22 where id in (1,2);

where条件中的id是数据库的主键范围,并且使用for update关键字,加了多个行锁,这个事务没有commit。

此时,开启了另外一个事务2,也更新id=1的用户的年龄:

begin;
update user set age=23 where id=1;
commit;

执行结果跟主键的情况也是一样的。

此时,开启了另外一个事务2,也更新id=2的用户的年龄:

begin;
update user set age=23 where id=2;
commit;

 执行结果跟主键的情况也是一样的。

 

6. 普通字段

当where条件用的数据库普通字段时。

该字段既不是主键,也不是索引。

开启一个事务1,在事务中更新age=22的用户的年龄:

begin;
select * from user where age=22 for update;
update user set age=22 where age=22 ;

where条件中的age是数据库的普通字段,并且使用for update关键字,加的是表锁,这个事务没有commit。

此时,开启了另外一个事务2,也更新age=22的用户的年龄:

begin;
update user set age=23 where age=22 ;
commit;

此时,执行事务2时,会一直阻塞等待事务1释放锁。

调整一下sql条件,查询条件改成age=23:

begin;
update user set age=23 where age=23 ;
commit;

此时,行事务3时,也会一直阻塞等待事务1释放锁。

也就是说,在for update语句中,使用普通字段作为查询条件时,加的是表锁,而并非行锁。

7. 空数据

当where条件查询的数据不存在时,会发生什么呢?

开启一个事务1,在事务中更新id=66的用户的年龄:

begin;
select * from user where id=66 for update;
update user set age=22 where id=66 ;

这条数据是不存在的。

此时,开启了另外一个事务2,也更新id=66的用户的年龄:

begin;
update user set age=23 where id=66 ;
commit;

 执行结果:

 

执行成功了,说明这种情况没有加锁。

总结

最后给大家总结一下select...for update加锁的情况:

  1. 主键字段:加行锁。

  2. 唯一索引字段:加行锁。

  3. 普通索引字段:加行锁。

  4. 主键范围:加多个行锁。

  5. 普通字段:加表锁。

  6. 查询空数据:不加锁。

如果事务1加了行锁,一直没有释放锁,事务2操作相同行的数据时,会一直等待直到超时。

如果事务1加了表锁,一直没有释放锁,事务2不管操作的是哪一行数据,都会一直等待直到超时。


                

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1153289.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt 安卓版本提供google play商店版本太旧更新方法

多击play商店版本,开启开发者模式,再点击更新play商店。会自动下载最新版安装。记得开梯子。

太极培训机构展示服务预约小程序的作用如何

太极是适合男女老幼的,很多地方也有相关的学校或培训机构,由于受众广且不太受地域影响,因此对培训机构来说,除了线下经营外,线上宣传、学员获取和发展也不可少。 接下来让我们看下通过【雨科】平台制作太极教培服务预…

面试算法45:二叉树最低层最左边的值

题目 如何在一棵二叉树中找出它最低层最左边节点的值?假设二叉树中最少有一个节点。例如,在如图7.5所示的二叉树中最低层最左边一个节点的值是5。 分析 可以用一个变量bottomLeft来保存每一层最左边的节点的值。在遍历二叉树时,每当遇到新…

Apollo上车实践:打造安全、高效、舒适的出行体验

上车实践 概述自动驾驶车辆适配线控标准协议开环验证车辆 自动驾驶车辆集成了解传感器布置与连接了解车辆标定了解传感器标定循迹实践 自动驾驶测试与调车了解车辆安全操作流程了解实车控制调试了解实车定位调试 福利活动 主页传送门:📀 传送 概述 通过…

C++设计模式_18_State 状态模式

State和Memento被归为“状态变化”模式。 文章目录 1. “状态变化”模式1.1 典型模式 2. 动机 (Motivation)3. 代码演示State 状态模式3.1 常规方式3.2 State 状态模式 4. 模式定义5. 结构( Structure )6. 要点总结7. 其他参考 1. “状态变化”模式 在组件构建过程中&#xf…

Apache ActiveMQ (版本 < 5.18.3) (CNVD-2023-69477)RCE修复方案/缓解方案

一、漏洞描述 Apache ActiveMQ 是美国阿帕奇(Apache)基金会的一套开源的消息中间件,它支持 Java 消息服务、集群、Spring Framework 等。 二、漏洞成因 ActiveMQ 默认开放了 61616 端口用于接收 OpenWire 协议消息,由于针对异常…

sqlite3 关系型数据库语言 SQL 语言

SQL(Structured Query Language)语言是一种结构化查询语言,是一个通用的,功能强大的关系型数据库操作语言. 包含 6 个部分: 1.数据查询语言(DQL:Data Query Language) 从数据库的二维表格中查询数据,保留字 SELECT 是 DQL 中用的最多的语句 2.数据操作语言(DML) 最主要的关…

视频下载工具Downie4 mac中文支持格式

Downie4 mac是一款视频下载工具。它支持下载各种视频网站上的视频,并且具有快速、稳定、易于使用的特点。 Downie支持下载各种视频网站上的视频,包括YouTube、Vimeo、Netflix、Hulu、Amazon等等。它具有快速、稳定的下载速度,可以帮助用户轻松…

HDFS架构介绍

数新网络_让每个人享受数据的价值浙江数新网络有限公司是一家开源开放、专注于云数据智能操作系统和数据价值流通的服务商。公司自主研发的DataCyber云数据智能操作系统,主要包括数据平台CyberData、人工智能平台CyberAI、数据智能引擎CyberEngine、数据安全平台Cyb…

手机app爬虫配置 (苹果手机)

近期在做某个项目,涉及到需要对手机app的进行数据爬取。在上一篇博文中,讲述了以模拟机为例的配置操作流程,这里将以苹果手机为例进行描述。 下面将讲述具体配置步骤 1、安装 抓包软件 fiddler (Fiddler | Web Debugging Proxy and Troubleshooting Solutions) ​ 下载后…

navicat15 恢复试用方法

1.运行,输入regedit,打开注册表 2.注册表中搜索 HKEY_CURRENT_USER\Software\PremiumSoft\NavicatPremium,删除下面的Registration15XCS文件夹 3.注册表中再搜索 HKEY_CURRENT_USER\Software\Classes\CLSID 然后拉到文件夹目录的最后&#x…

实时视频混合和映射:Resolume Arena 6(专业的VJ)中文

Resolume Arena 6是一款专业的实时视频混合和映射软件,广泛应用于音乐表演、舞台演出、俱乐部活动等场合,打造令人惊叹的视觉效果和图像投影。它支持实时混合多个视频源,拥有视频映射功能以及提供多样实时效果和过渡效果,让用户能…

MySQL的MSI安装

MySQL的MSI安装 文章目录: MySQL的MSI安装材料准备:一、MySQL安装的准备工作二、MySQL的配置三、MySQL安装验证1、CMD命名验证2、MySQL 8.0 Command Line Client验证 材料准备: 1、x64或x86电脑 2、MySQL安装包 一、MySQL安装的准备工作 M…

Unity 粒子特效-第一集-五角星发射特效

一、基础理解 1.粒子特效的意思是,发射很多小的东西,组成一个效果 2.主要可以分成两种 a.一直循环(如上图) b.发射状 二、案例视频 今天我们做一个发射的五角星 三、案例分析 我们仔细来分析一下这个五角星的功能 1.每次显示1秒…

Android体育场馆预约系统+全套手把手视频教程

【项目功能介绍】 功能列表: 本系统包含后台管理和前端app双端系统, 本系统包含三个角色: 管理员,员工,app用户。 后台管理员的功能包含: 登录, 退出, 场馆管理,添加场馆,修改场馆,禁用启用场馆; 场馆场地管理,添加场馆场地,修改场馆场地,启用禁用场馆场地; 订单管理,确定订单…

Python自动化运维监控——批量监听页面发邮件(自由配置ini文件+smtplib)

一、程序样式 1.listen.ini配置文件 2.监控页面 3.日志 二、核心点 smtplib库:这里使用了smtp.qq.com与smtp.163.com两个发送邮件的地址,使用邮箱用户名与授权码来实现登录,端口都使用465,最后抛出异常,finally里…

分享一下微信小程序抽奖链接怎么做

标题:微信小程序抽奖链接制作全攻略,轻松玩转营销抽奖活动 一、引言 在当今的数字化时代,抽奖活动已经成为一种高效的市场营销策略,而微信小程序作为一个功能强大的移动端平台,为企业和个人提供了制作抽奖链接的便捷…

如何能够根据现有业务,结合代码清晰的知道技术实现是如何去实现的,方法论和切入点是什么?

要深入了解现有业务系统的技术实现,特别是当你想要准确理解某个具体功能或组件是如何实现的时候,你可以采取以下的方法论和切入点: 1. 文档和设计说明 首先查阅相关的技术文档和设计说明,这些文档通常会详细描述系统的架构、各个…

STM32———USART串口控制LED灯亮灭

1.硬件设计流程 2.程序设计流程 1.串口初始化时钟使能:RCC_APBxPeriphClockCmd(); GPIO初始化时钟使能:RCC_AHBxPeriphClockCmd();2.GPIO端口模式配置:GPIO_Init();3.串口参数初始化:USART_Init();4.串口使能:USART_C…

如何在React项目中引用less

安装less npm install less less-loader --save-dev暴露 webpack 文件 利用 npx create-react-app 搭建的 React 项目,默认隐藏 webpack 配置文件,引入 less 需要修改 webpack 配置文件,因此我们需要执行命令暴露 webpack 配置文件。 请先将…