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

select...for update 锁表了?

在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不管操作的是哪一行数据,都会一直等待直到超时。

相关文章:

select...for update 锁表了?

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

使用ControlNet生成视频(Pose2Pose)

目录 ControlNet 介绍 ControlNet 14种模型分别是用来做什么的 ControlNet 运行环境搭建 用到的相关模型地址 ControlNet 介绍 ControlNet 是一种用于控制扩散模型的神经网络结构,可以通过添加额外的条件来实现对图像生成的控制。它通过将神经网络块的权重复制到…...

基于Docker使用Minikube

1. 查看并操控Minikube状态信息 Minikube相当于docker中的一个container,可以在Docker Desktop中看到并操控Minikube container的相关状态: 通过以下命令查看当前docker中的container: % docker ps CONTAINER ID IMAGE …...

Stable Diffusion系列(一):古早显卡上最新版 WebUI 安装及简单操作

文章目录 Stable Diffusion安装AnimateDiff插件适配sdxl模型适配 Stable Diffusion使用插件安装界面设置基础文生图加入lora的文生图 Stable Diffusion安装 我的情况比较特殊,显卡版本太老,最高也就支持cuda10.2,因此只能安装pytorch1.12.1&…...

ruoyi框架前端vue部署生产环境教程

前端有子目录,后端有项目名称,请看第3种 第1种 前端nginx没有子目录,后端也没有访问的项目名。这种是最简单的。 vue.config.js 只需要修改target中的IP和端口,就是后端访问的IP和端口 # vue.config.js devServer: {host: 0.…...

leetcode第369周赛

2917. 找出数组中的 K-or 值 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 nums 中的 K-or 是一个满足以下条件的非负整数: 只有在 nums 中,至少存在 k 个元素的第 i 位值为 1 ,那么 K-or 中的第 i 位的值才是 1 。 返回 nums …...

如何在维格云中自动新增一行或多行数据?

简介​ 在日常使用维格云中,通常会出现一张表中有数据发生变化时,需要另一张表同时新增一些数据,比如: 项目管理中,每新增一个项目,都要在任务表中产生若干个固定的任务;或一个任务要自动生成若干子任务当一笔订单状态变为成交后,可能要在客户成功表中新增一行记录;帮…...

Three.js 开发引擎的特点

Three.js 是一个流行的开源 3D 游戏和图形引擎,用于在 Web 浏览器中创建高质量的三维图形和互动内容。以下是 Three.js 的主要特点和适用场合,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作…...

k8s声明式资源管理方式

Kubernetes 支持 YAML 和 JSON 格式管理资源对象 JSON 格式:主要用于 api 接口之间消息的传递 YAML 格式:用于配置和管理,YAML 是一种简洁的非标记性语言,内容格式人性化,较易读 YAML 语法格式: ●大小写…...

unity性能优化__Statistic状态分析

在Unity的Game视图右上角,我们会看到有Stats选项,点击会出现这样的信息 我使用的Unity版本是2019.4.16 一、Audio,顾名思义是声音信息 1:Level:-74.8dB 声音的相对强度或音量。通常,音量级别以分贝(dB&a…...

Linux Spug自动化运维平台公网远程访问

文章目录 前言1. Docker安装Spug2 . 本地访问测试3. Linux 安装cpolar4. 配置Spug公网访问地址5. 公网远程访问Spug管理界面6. 固定Spug公网地址 前言 Spug 面向中小型企业设计的轻量级无 Agent 的自动化运维平台,整合了主机管理、主机批量执行、主机在线终端、文件…...

3DES算法

简介 本文基于.NET的C#实现3DES算法的加密和解密过程。可以用在加密软件、加密狗等。 代码下载链接:https://download.csdn.net/download/C_gyl/88487942 使用 第一种方法 加密 KeySize:128(16字节),192(24字节&#x…...

手机电池寿命检测

安卓 - 应用商店下载“安兔兔” -accubattery 下载地址 accubattery汉化版下载-Accubattery pro中文免费版(电池检测)下载 v1.5.11 安卓专业版-IT猫扑网...

Vue项目搭建及使用vue-cli创建项目、创建登录页面、与后台进行交互,以及安装和使用axios、qs和vue-axios

目录 1. 搭建项目 1.1 使用vue-cli创建项目 1.2 通过npm安装element-ui 1.3 导入组件 2 创建登录页面 2.1 创建登录组件 2.2 引入css(css.txt) 2.3 配置路由 2.5 运行效果 3. 后台交互 3.1 引入axios 3.2 axios/qs/vue-axios安装与使用 3.2…...

AVL树、红黑树的介绍和实现[C++]

本文主要对AVL树和红黑树的结构和实现方法进行一定的介绍,仅实现部分接口。 目录 一、AVL树 1.AVL树的概念 2.AVL树节点的定义 3.AVL树的插入 4.AVL树的旋转 1. 新节点插入较高左子树的左侧——左左:右单旋 2. 新节点插入较高右子树的右侧——右…...

meta分析的异质性检验指标如何计算?

一、什么是异质性? 广义:描述参与者、干预措施和一系列研究间测量结果的差异和多样性,或那些研究中内在真实性的变异。 狭义:统计学异质性,用来描述一系列研究中效应量的变异程度,也用于表明除仅可预见的…...

如何在mac 安装 cocos 的 android环境

基本概念: Java: Java 是一种编程语言,由Sun Microsystems(现在是 Oracle Corporation)开发。Java 是一种跨平台的语言,可以用于开发各种应用程序,包括 Android 应用程序。Android 应用程序的核心代码通常用…...

作为网工有必要了解一下什么是SRv6?

什么是SRv6? 【微|信|公|众|号:厦门微思网络】 【微思网络http://www.xmws.cn,成立于2002年,专业培训21年,思科、华为、红帽、ORACLE、VMware等厂商认证及考试,以及其他认证PMP、CISP、ITIL等】 SRv6&…...

Jmeter(十八):硬件性能监控指标详解

硬件性能监控指标 一、性能监控初步介绍 性能测试的主要目标 1.在当前的服务器配置情况,最大的用户数 2.平均响应时间ART,找出时间较长的业务 3.每秒事务数TPS,服务器的处理能力 性能测试涉及的内容 1.客户端性能测试:web前…...

【ARM Trace32(劳特巴赫) 使用介绍 2 -- Trace32 cmm 脚本基本语法及常用命令】

文章目录 Trace32 CMM 概述1.1 Trace32 系统命令 SYStem1.1.1 Trace32 SYStem.CONFIG1.1.2 SYStem.MemAccess1.1.3 SYStem.Mode1.1.3.1 TRST-Resets the JTAG TAP controller and the CPU internal debug logic1.1.3.2 SRST- Resets the CPU core and peripherals 1.2 Trace32 …...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

dify打造数据可视化图表

一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

docker 部署发现spring.profiles.active 问题

报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...