本文介绍: 1.for update是什么 ?2. 实际项目中的应用场景 ?3.表锁还是行锁 本文将全面给大家讲解以上问题

一、for update 是什么?

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

B站视频地址:【数据库 for update 详细教程(行锁还是表锁问题演示)-哔哩哔哩】 https://b23.tv/4XToMlN

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

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&gt;()
					.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_9343.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注