场景

拼团功能,当 A 客户开团之后(两人团),如果 B 和 C 同时支付,如何规避两人同时将拼团人数增加。

Laravel 中 sharedLock 与 lockForUpdate 的区别

  • sharedLock 对应的是 LOCK IN SHARE MODE
  • lockForUpdate 对应的是 FOR UPDATE

sharedLock 与 lockForUpdate 相同的地方是,都能避免同一行数据被其他 transaction 进行 update。

不同的地方是:

  • sharedLock 不会阻止其他 transaction 读取同一行
  • lockForUpdate 会阻止其他 transaction 读取同一行 (需要特别注意的是,普通的非锁定读取读取依然可以读取到该行,只有 sharedLock 和 lockForUpdate 的读取会被阻止。)

即 sharedLock locks only for write, lockForUpdate also prevents them from being selected

这样做是有意义的,例如,两个 transaction 要更新同一个计数器,如果不使用 lockForUpdate, 会导致两个 transaction 同时读到同一个初始值,然后在应用层逻辑中增加计数之后,提交到数据库中,后者的操作会覆盖掉前者的操作。

如何测试

在 MySQL 命令行终端操作一个表

mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> select * from users for update;
+----+------+
| id | name |
+----+------+
|  1 | tom  |
|  2 | bob  |
+----+------+

这时再开一个命令行终端

mysql> select * from users for update;
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from users lock in share mode;
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted

你会发现,无论是 for update 还是 lock in share mode 都无法读取到数据,更加确切地说是,查询被阻塞了。

只有在第一个终端执行

commit;

第二个终端才能得到数据返回。

需要注意的是,发起者必须在 transaction 里上锁才有效,如果不是在 transaction 中,上锁是无效的。但是,第二个人无论是不是在 transaction 里,都会被锁。

我依然有几个疑问

  • Laravel 如何设置数据库操作超时时间
  • 什么场景下适合使用 sharedLock 呢?
  • sharedLock,lockForUpdate 与 Pessimistic Locking 是什么关系
  • Pessimistic locking(悲观锁) 与 Optimistic locking(乐观锁)的区别

如何测试 Laravel

A 用户,在浏览器里访问接口 (模拟支付回调),此时对数据表中某一行锁住,进行 30s 操作,然后提交事务。

B 用户,在浏览器里访问同一接口 (模拟支付回调),其无法修改该行。对应的返回是什么?

会一直 wait 到数据库操作超时。

那么问题来了,Laravel 如何设置数据库操作超时时间?

简单的测试方法,是在命令行中开两个 artisan tinker 窗口,分别执行

DB::transaction(function () {echo 1;User::where('id', 33)->lockForUpdate()->get();echo 2;sleep(10);
});

你会发现第二个 tinker 窗口中的 get 操作,需要等到第一个 transaction 执行完毕之后,才能得到查询结果。

需要注意的是,不在 transaction 中的 lockForUpdate 操作,是没有锁效果的。

真实场景,防止用户重复提现

DB::transaction(function () use ($user, &$user_award) {$user_award = UserAward::where([['user_id', $user->id],['status', 0],])->lockForUpdate()->first();if ($user_award) {$user_award->status = 1;        // 提现中状态$user_award->save();}
});if (!is_null($user_award)) {$amount = $user_award->money * 100;
}

事务与锁的关系

事务中涉及的操作都会加上锁?

如果默认会加上锁,那么默认会加上什么锁呢?

事务中涉及的操作,不需要显式加锁?

要理清其中关系,就需要了解事务的四种隔离级别:

  • 未提交读(Read uncommitted)
  • 已提交读(Read committed)
  • 可重复读(Repeatable read)
  • 可串行化(Serializable )

MySQL 默认的是:可重复读(Repeatable read)

参考

  • Innodb中的事务隔离级别和锁的关系 -
  • Database: Query Builder - Laravel - The PHP Framework For Web Artisans
  • [https://stackoverflow.com/questions/34556511/laravel-lockforupdate-pessimistic-locking]
  • SELECT LOCK IN SHARE MODE and FOR UPDATE - Percona Database Performance Blog
  • transactions - MySQL InnoDB: Difference Between FOR UPDATE and LOCK IN SHARE MODE - Stack Overflow

转载地址:https://www.sunzhongwei.com/using-laravel-sharedlock-and-lockforupdate-for-table-row-locks

使用 Laravel sharedLock 与 lockForUpdate 进行数据表行锁相关推荐

  1. 使用CommandArgument查找数据表行的数据库表record_id

    在处理最近的项目时,我发现CommandArgument属性可以有多有用. 我需要确定数据网格中显示的行的record_id. 当用户单击"编辑图像按钮"时,我需要将用户重定向到& ...

  2. mysql某个表被行锁了_一文搞懂MySQL行锁、表锁、间隙锁详解

    准备工作 创建表 tb_innodb_lock drop table if exists test_innodb_lock; CREATE TABLE test_innodb_lock ( a INT ...

  3. select for update加了行锁还是表锁?

    前言 大家,我是田螺. 最近在开发需求的时候,用到了select......for update.在代码评审的时候,一位同事说 ,唯一索引+一个非索引字段,是否可能会锁全表呢?本文田螺哥将通过9个实验 ...

  4. java实现表锁行锁

    背景 今天做需求时遇到一个统计场景,接口将用户请求记录缓存在concurrentHashmap,其中用户名作为map的Key,value为统计结果类的对象,更新此map的时候使用分段锁(通过用户名取h ...

  5. 【Laravel】Laravel-admin后台框架-2创建数据表建立模块增删改查CURD(2)

    前言 前面的操作我们已经能够 安装Laravel-admin 创建数据表并生成模型 修改模型实现按业务写入数据 可以参考之前的文章 [Laravel]Laravel-admin后台框架-2创建数据表建 ...

  6. Laravel学习笔记4,文件上传,分页,验证码,数据表和迁移

    目录 一.文件上传 二.数据分页 三.验证码 Return Image Return URL Return HTML 六.响应处理 一.文件上传 在laravel, 里面实现文件的上传是很简单的,压根 ...

  7. php怎么创建表命令行,laravel使用命令行结合代码创建数据表的方法

    laravel使用命令行结合代码创建数据表的方法 发布时间:2021-01-19 10:12:17 来源:亿速云 阅读:91 作者:小新 这篇文章主要介绍laravel使用命令行结合代码创建数据表的方 ...

  8. php怎么创建表命令行,laravel创建数据表(使用命令行结合代码)

    下面由Laravel框架教程栏目给大家介绍laravel 创建数据表,希望对需要的朋友有所帮助! 虽然可以直接在数据库中创建数据表,但是不便于以后项目的迁移.现使用命令行结合代码的方式来进行生成. 1 ...

  9. 是先设计mysql表再进行php代码_PHP与RBAC设计思路,数据表设计与源码讲解

    权限系统模块对于互联网产品是一个非常重要的功能,可以控制不同的角色合理的访问不同的资源从而达到安全访问的作用 权限控制有哪些模型ACL RBAC 基于角色的访问控制 从上图我们可以看出,ACL是用户和 ...

最新文章

  1. 在IE7中无效的解决办法
  2. IBM 揭晓全球第一项 2纳米芯片技术,为半导体领域实现重大突破
  3. .net环境iis执行php,十步!轻松搞定IIS+PHP环境
  4. 大战设计模式【13】—— 组合模式
  5. python plot函数label_python – Matplotlib Contour Clabel位置
  6. Color the ball(树状数组区间更新+单点求值)
  7. python零基础好学吗-Python零基础好学吗?零基础如何学习Python?
  8. Spring Bean的加载过程以及一些生命周期
  9. 软件是怎么控制硬件的?
  10. 苹果手机测距离_手机传感器怎样运作 手机传感器工作原理【介绍】
  11. k8s集群配置域名证书支持https与http
  12. 2020.10小米校招一面
  13. java大数据量调优(超赞值得收藏)
  14. MySql中增加注释、追加注释、修改注释、查看注释
  15. vue初始化页面闪动问题
  16. 浅谈__getattribute__与__getattr__
  17. Linux下离线安装Google Chrome
  18. 凯利边带(Kelly Sidebands)
  19. [认证 授权] OAuth2授权
  20. 聊聊EXCEL里的数据分析

热门文章

  1. Java 面向对象:重写的理解
  2. SpringSecurity使用SpringBoot简单使用
  3. 一道关于String的易错习题
  4. Python程序员面试必备常用问题答案及解析
  5. loadrunner-2-9添加事务
  6. Jmeter - 服务器性能检测
  7. 根据Ip获取城市帮助类
  8. Large Memory Footprints on AIX
  9. 浅谈C++ STL中的优先队列(priority_queue)
  10. 16-margin的用法