Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > mysql的for update用法

解读mysql的for update用法

作者:韩师学子--小倪

这篇文章主要介绍了解读mysql的for update用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

mysql的for update用法

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) 场景

场景一 

当前使用for UPDATE查询,其他地方查询   --   其他地方也使用for UPDATE会堵塞,其他地方未使用for UPDATE不会堵塞

1. 当前A(不区分是否为事务里)使用for UPDATE查询

SELECT * FROM saas_employee_label_person where id = 1 for UPDATE

1.1 其他地方B(不在上一个连接里或事务里,不区分是否为事务里)使用for UPDATE 查询(需要获取锁)

SELECT * FROM saas_employee_label_person where id = 1 for UPDATE

会发生堵塞等待前一个A锁释放(A事务提交,或者A结束运行(A为非事务场景))

1.2 其他地方C(不区分是否为事务里)不使用for UPDATE 查询(无需获取锁)

SELECT * FROM saas_employee_label_person where id = 1

不会堵塞,可以查询

场景二 

当前使用for UPDATE查询,其他地方UPDATE更新   --   会堵塞等待

2. 当前A(不区分是否为事务里)使用for UPDATE查询

SELECT * FROM saas_employee_label_person where id = 1 for UPDATE

2.1 其他地方B(不区分是否为事务里)使用UPDATE更新数据

UPDATE saas_employee_label_person set employee_id = 1111 where id = 1;

会发生堵塞等待前一个A锁释放(A事务提交,或者A结束运行(A为非事务场景))

场景三 

当前事务使用UPDATE更新,其他地方使用for UPDATE查询   --   会堵塞等待

3. 当前事务A 使用UPDATE更新

BEGIN;
UPDATE saas_employee_label_person set employee_id = 11121 where id = 1;

3.1 其他地方B(不区分是否为事务里)使用 for UPDATE查询

SELECT * FROM saas_employee_label_person where id = 1 for UPDATE

会发生堵塞等待前一个事务A提交才可以获得锁

场景四

当前非事务使用UPDATE更新,其他地方使用for UPDATE查询   --   不会堵塞

4. 当前A(非事务下) 使用UPDATE更新

UPDATE saas_employee_label_person set employee_id = 11121 where id = 1;

4.1 其他地方B(不区分是否为事务里)使用 for UPDATE查询

SELECT * FROM saas_employee_label_person where id = 1 for UPDATE

不会堵塞,前一个update先执行完,所以不影响,这里一定是update先执行完在走for UPDATE查询的场景,否者就是场景二了

场景五

当前普通查询,其他地方使用for UPDATE查询   --   不影响,不会堵塞

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文