Mysql for Update

forupdate用于数据库操作中,可在高并发场景下确保数据准确性,通过为数据行加锁防止多个事务同时更新同一数据,尤其适用于涉及金钱和库存的操作。本文解析forupdate的工作原理,使用方法及注意事项。

背景

for update是在数据库中上锁用的,可以为数据库中的行上一个排它锁。当一个事务的操作未完成时候,其他事务可以读取但是不能写入或更新。

for update的使用场景
如果遇到存在高并发并且对于数据的准确性很有要求的场景,是需要了解和使用for update的。

比如涉及到金钱、库存等。一般这些操作都是很长一串并且是开启事务的。如果库存刚开始读的时候是1,而立马另一个进程进行了update将库存更新为0了,而事务还没有结束,会将错的数据一直执行下去,就会有问题。所以需要for upate 进行数据加锁防止高并发时候数据出错。

记住一个原则:一锁二判三更新

for update如何使用
使用姿势:

select * from table where xxx for update
for update的锁表
InnoDB默认是行级别的锁,当有明确指定的主键时候,是行级锁。否则是表级别。

例子: 假设表foods ,存在有id跟name、status三个字段,id是主键,status有索引。

例1: (明确指定主键,并且有此记录,行级锁)

SELECT * FROM foods WHERE id=1 FOR UPDATE;
SELECT * FROM foods WHERE id=1 and name=’咖啡色的羊驼’ FOR UPDATE;
例2: (明确指定主键/索引,若查无此记录,无锁)

SELECT * FROM foods WHERE id=-1 FOR UPDATE;
例3: (无主键/索引,表级锁)

SELECT * FROM foods WHERE name=’咖啡色的羊驼’ FOR UPDATE;
例4: (主键/索引不明确,表级锁)

SELECT * FROM foods WHERE id<>’3’ FOR UPDATE;
SELECT * FROM foods WHERE id LIKE ‘3’ FOR UPDATE;
for update的注意点
1.for update 仅适用于InnoDB,并且必须开启事务,在begin与commit之间才生效。

2.要测试for update的锁表情况,可以利用MySQL的Command Mode,开启二个视窗来做测试。

for update的疑问点
当开启一个事务进行for update的时候,另一个事务也有for update的时候会一直等着,直到第一个事务结束吗?
答:会的。除非第一个事务commit或者rollback或者断开连接,第二个事务会立马拿到锁进行后面操作。

如果没查到记录会锁表吗?

答:会的。表级锁时,不管是否查询到记录,都会锁定表。

for update 和 for update nowait区别(前者阻塞其他事务,后者拒绝其他事务)

for update锁住表或者锁住行,只允许当前事务进行操作(读写),其他事务被阻塞,直到当前事务提交或者回滚,被阻塞的事务自动执行
for update nowait 锁住表或者锁住行,只允许当前事务进行操作(读写),其他事务被拒绝,事务占据的statement连接也会被断开
 

### MySQL 中 `FOR UPDATE` 使用说明 #### 作用与应用场景 `SELECT ... FOR UPDATE` 是 SQL 语言中的一种语句,用于在数据库事务处理中控制并发访问。这种语句通常用在需要对数据库中的记录进行更新操作的场景中[^1]。 当在一个事务中执行 `SELECT ... FOR UPDATE` 查询时,查询返回的结果集中的每一行都会被加上排他锁(X 锁)。这意味着其他事务无法再获取这些行上的任何类型的锁,直到当前事务结束并释放锁为止。这可以防止其他事务在这段时间内修改或删除这些行的数据。 #### 自动加锁机制 对于 `INSERT`、`UPDATE` 和 `DELETE` 操作,InnoDB 存储引擎会自动给涉及的数据加排他锁;而对于一般的 `SELECT` 语句,默认情况下 InnoDB 不会对读取的数据加任何形式的锁。但是,如果希望在读取某些特定数据的同时阻止其他事务对其进行更改,则可以通过显式的 `SELECT ... LOCK IN SHARE MODE` 或者 `SELECT ... FOR UPDATE` 来实现这一点[^3]。 #### 示例代码 下面是一个存储过程的例子,展示了如何使用 `SELECT ... FOR UPDATE`: ```sql CREATE DEFINER=`root`@`%` PROCEDURE `SELECT...FOR UPDATE_001`() BEGIN -- 初始化变量 SET @sum := 0; -- 开启新事物 START TRANSACTION; -- 对指定条件下的记录加排它锁 SELECT * FROM dept_inf WHERE ID = 11 FOR UPDATE; -- 循环增加计数器值 (模拟长时间运行的任务) WHILE @sum < 1000000 DO SET @sum = @sum + 1; END WHILE; -- 更新另一条记录 UPDATE dept_inf SET NUM = NUM + 1 WHERE ID = 13; -- 输出最终结果 SELECT @sum; -- 提交所有变更到永久存储介质 COMMIT; END ``` 此示例演示了如何通过 `START TRANSACTION` 命令开启一个新的事务,在该事务内部先利用 `SELECT ... FOR UPDATE` 获取某一行的独占权限,接着进行了大量的计算工作以及后续对该表其它行的操作,最后调用了 `COMMIT` 将整个过程中所做的全部改动正式写入数据库[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值