文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

for update 详解及实战

2023-08-20 20:04

关注

一、for update 是什么?

“SELECT … FOR UPDATE” 是一种在 SQL 中常用的锁定查询语句。它可以在查询数据时同时对查询结果中的记录加上排他锁 ,防止其他事务修改或删除这些记录。使用方法为在 SELECT 语句中加上 FOR UPDATE 子句。
例如:
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
这会查询 accounts 表中 id 为 1 的记录,并对这些记录加上排他锁。

二、我们通常什么情况下会用到它?

1 .在我们的实际业务场景中,有些情况并发量不太高,为了保证数据的正确性,使用悲观锁也可以

1.分布式下并发扣减库存的操作(原来我们系统运用乐观锁限制 但是后来发现多扣减的问题 后来改用了 for updte 行锁的方式) 这个我会用一个案例来讲解说明2.用户扣减积分,系统自动赠送积分的并发情况,有必要加悲观锁限制一下,防止出现积分加错的情况发生.

三、select……for update会锁表还是锁行?

我将从三方面演示这个问题(以下内容都为本人亲测 mysql 5.7 数据库引擎为 innodb 隔离级别为数据库默认隔离级别 (可重复读) )
首先需要关闭数据库事务的自动提交变更为手动提交事务 set autocommit=0
sql执行脚本:
在这里插入图片描述

上面需要sql执行脚本的可以联系我 这里我就直接粘贴图片了
在这里插入图片描述

以下三种情况都需要打开两个测试窗口

1.有主键的情况下

窗口1:执行如下命令:

start transaction ;select service_name from chenwx_code where id=1 for update;

将id为1的行数据锁住 等待执行commit 语句
在这里插入图片描述
窗口2:执行如下命令:

update chenwx_code set is_deleted = is_deleted - 1 where id = '2';update chenwx_code set is_deleted = is_deleted - 1 where id = '1';

上面的命令
id 为 2可以正常执行成功
id为1 的数据会阻塞等待。

测试id 为 2修改操作正常执行成功
在这里插入图片描述
窗口2 因为开启了事务手动提交所以需要正常手动commit 数据才能执行修改数据操作

执行更新id为1的数据显示锁等待超时 超过一定时间会显示锁等待超时错误
在这里插入图片描述

1 .以上说明有主键的情况下执行for update语句利用主键开启事务查询会锁住当前行数据 ,不会锁住其他行数据

现在执行窗口2行锁事务执行没有超时的情况下正常扣减的情况
在这里插入图片描述

上面 主键1和主键2的is_deleted值都为 5
执行窗口1:
执行 1 .start transation 2.和for update 查询语句 可以看到返回主键id为1的 is_deleted 的值为5

在这里插入图片描述
执行窗口2:
执行 1 .start transation 2.和 for update id 为1的修改语句 可以看到数据显示正在执行一直等待中…

在这里插入图片描述
接着在执行窗口1 提交事务 commit 显示提交成功
在这里插入图片描述
窗口2显示返回更新成功 说明窗口2的事务一直在阻塞等待窗口1的事务提交
在这里插入图片描述
最终数据返回执行结果为 主键id为1的 is_deleted值减1成功返回4
在这里插入图片描述

2.有普通索引或者唯一索引的情况下

亲测普通索引和唯一索引都可以的 执行情况和主键id是一致的下面是示例
现在拿普通索引来看一下执行情况
窗口1:执行start transaction 和 根据索引查找for update语句 执行结果返回is_deleted为4的执行结果

窗口2:执行start transaction 和 根据索引字段为service_name= base2的值更新字段is_deleted的值减1正常执行并且返回成功
在这里插入图片描述
接着在修改索引字段为service_name= base1的值更新字段is_deleted的值减1则显示这行数据处于阻塞状态
在这里插入图片描述
此时执行窗口1执行commit操作 提交返回成功
在这里插入图片描述
然后快速的打开窗口2显示修改成功
在这里插入图片描述
窗口2提交commit操作则显示成功
在这里插入图片描述
此时查看表里面service_name=base1的数据中的is_deleted字段变为3 说明修改大成功
在这里插入图片描述

3.没有索引的情况下

窗口1:执行start transaction 和 根据没有索引的字段执行 for update查询语句 执行结果返回service_name=base1的这行所有数据
在这里插入图片描述
窗口2:执行start transaction和修改service_name=base2的这行数据则显示base2的数据处于阻塞状态
因为修改的数据不是同一行数据也就是说不是锁住的行数据 所以说是表锁住了而不是行锁

在这里插入图片描述
接在窗口1执行commit操作提价数据
在这里插入图片描述
紧接着打开窗口2 此时窗口2修改的这一行数据已经显示执行成功了所以说是表锁住了
在这里插入图片描述

四、项目中的真实应用

1.首先开启spring事务

2.执行修改操作(业务逻辑) (根据主键或者有索引的字段进行for update查询 此操作为行锁)

3.最后返回执行结果给前端做展示

代码情况如下所示

//开启事务   spring默认的隔离级别 @Transactional(rollbackFor = Exception.class)//根据业务执行逻辑如下//1 先使用行锁 锁住当前行数据GoodsSku goodsSku = goodsSkuService.getBaseMapper().selectList(new LambdaQueryWrapper<GoodsSku>().eq(GoodsSku::getId, proOrderGenerateSpuVo.getSkuId()).select(GoodsSku::getStock, GoodsSku::getId, GoodsSku::getVersion).last(" for update")//2 在执行修改库存操作boolean result = goodsSkuService.updateById(goodsSku);//3 提交返回数据return vo

五、想要使用for update一定要开启事务否则不生效

总结

希望大家多多支持我是维新的博客 有什么问题可以咨询我

来源地址:https://blog.csdn.net/qq_39220971/article/details/130245812

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯