MySQL中的select for update大家应该都有所接触,但什么时候该去使用,以及有哪些需要注意的地方会有很多不清楚的地方,我把我如何使用和查询到的文档在此记录。

作用

select本身是一个查询语句,查询语句是不会产生冲突的一种行为,一般情况下是没有锁的,用select for update 会让select语句产生一个排它锁(X), 这个锁和update的效果一样,会使两个事务无法同时更新一条记录。

什么时候使用

我认为的错误的用法

在网上看到一篇文章, 里面讲到用select for update来产生一个悲观锁,保证库存的一致性,其他update在更新的时候本身就有悲观锁,不会让另外一个事务更新,如果按照他的写法update goods set stock = stock - 1 where id = 1;是没必要先去查询的

我认为的正确的用法(1)

有时我们确实需要先将数据查询出来,然后再去更新,但我们不想的是,我刚查询完结果没还更新,这时被其他事务更新了,例如上面的例子,如果我想先查询库存,确认库存是否足够,如果足够就去更新,不够就返回一个错误

begin;
select * from goods where id = 1; // 检查库存足够代码 update goods set stock = stock - 1 where id = 1;
commit;

如果不用for update的情况下,在检查库存时,被其他事务更新了库存,就会产生库存不足,但是当前事务以为充足的情况发生, 所以使用for update先锁住这条记录,其他事务不能去更改这条记录直到当前事务提交

我认为的正确的用法(2)

在我们实际业务中,一个订单要扣除多个补剂的库存,这时要用事务保证一个订单多个补剂同时扣除成功或者同时失败,可能会出现这样的情况,M订单需要补剂a,b,c三种补剂,N订单需要c,e,a三种补剂,这时两个事务同时执行,M事务扣除ab库存,N事务库存c,e库存,因为update会产生排它锁阻止其他事务更新当前事务已经更新的记录,所以这会产生死锁,M在等待获取c的锁,N在等待获取a的锁,在订单比较多的情况下,这种冲突很容易出现,我的解决方法是当M需要a,b,c三种补剂时,使用select for update锁定三条记录,此时N订单select for update获取不到c的锁直到M订单事务提交

2022.03.29 Update: 经过很长一段时间工作之后,我发现我认为的正确用法(2)是错误的,这个和select for update没有关系,关键是要对共享资源进行排序,例如:有a-z共26中补剂,M订单需要a、d、e,N订单需要d、h、z,这这种情况中,谁先拿到冲突的资源谁会先执行完,因为冲突的资源后面的资源肯定不是冲突的,也就是说只使用事务+多个update也可以实现

至于其他的用法可以我后面遇到会再总结进去

注意事项

  • select for update会根据where条件来锁多条记录, 根据where条件的字段是不是索引来决定锁定表还是锁定行,同时根据是聚簇索引还是二级索引和查询条件(范围查询还是精确查询)来决定锁定特定的行还是一个范围内的行
  • 当锁定范围的行时会有gap lock和next-key来防止插入新的行参考StackOverFlow
  • SELECT * FROM information_schema.innodb_trx \G 使用该语句可以查询某个事务锁了几个表,锁了几个行

参考

[1] MySQL InnoDB存储引擎(三):锁及事务模型

[2] SELECT FOR UPDATE作用字段提问

最新文章

  1. ASP.Net MVC开发基础学习笔记:四、校验、AJAX与过滤器
  2. WriteFile实现下载
  3. archlinux locale-gen 命令出错
  4. Android apk 的安装过程
  5. 限额类费用报销单N+1原则
  6. 关于bootstrap--表格(table的各种样式)
  7. eclipse中默认的提示键
  8. Git 系列(五):三个 Git 图形化工具
  9. CSharp Oracle 登陆
  10. [翻译] 编写高性能 .NET 代码--第五章 通用编码与对象设计 -- 类 vs 结构体
  11. JSP 学习总结 03 核心组件 Servlet
  12. C#+EntityFramework编程方式详细之Model First
  13. IP通信基础课堂笔记----关于数链层
  14. RPC web service
  15. 【C#数据结构系列】栈和队列
  16. 转:PHPStorm+XDebug进行调试图文教程
  17. 机器学习初入门02 - Pandas的基本操作
  18. Python nose单元测试框架结合requests库进行web接口测试
  19. jquery自动填充输入框
  20. [MongoDB]------windos远程服务器部署连接

热门文章

  1. 采用docker方式安装ElastAlert,图形化配置告警规则----具体内容有删改,仅供查看
  2. centos7安装sonarqube-9.2.4
  3. Logstash:如何处理 Logstash pipeline 错误信息
  4. Linux make编译
  5. 定制开发 ERP 的优势有哪些?
  6. pthread_mutex_t & pthread_cond_t 总结
  7. Rdt2.1 和 Rdt2.2的详细解释
  8. Docker | 容器互联互通
  9. LeetCode------移动零(5)【数组】
  10. AI带你省钱旅游!精准预测民宿房源价格!