mysql的并发问题,如何同时将100条数据分给100个不同的人?

场景模拟

假如code 表中有100条数据,用户调用一次接口就会修改code表中user_id=0的数据并改为当前用户的user_id

参考

mysql 的innodb的行级锁是按索引查询,无索引将会升级为表级锁!
不确定使用相同where条件limit 1是否会获得同一条数据!

问题

在高并发的环境下,如何使用事务和锁同时修改这100条数据?环境为laravel9+mysql innodb

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
最佳答案

你这不是个典型的出列入列嘛!

首先表中有100条数据 user_id=0 对吧? 采用抢占式分配数据,如果你用表锁的话,高并发的话失败成功率太高了。

不如直接把这 user_id=0 的 100条 id 放入 redis list,通过 push pop 的方式来分配数据,这样数据库既没有压力,速度也快很多。只不过需要写一个脚本把这100条 user_id=0 的先入列到 redis

// Redis push
$rows = Code::where('user_id', 0)->get();
$redis = new Redis();
foreach($rows as $row) {
    $redis->rpush('user_id_0_queue', $row->id);
}
// Redis pop
if($id = $redis->lpop('user_id_0_queue')) {
    Code::where('id', $id)->update(['user_id' => Auth::id()]);
} else {
    return '号都发完啦!';
}
1年前 评论
MArtian (作者) 1年前
随波逐流 1年前
kis龍 1年前
yyy123456 1年前
UpGod (楼主) 1年前
讨论数量: 9

你这不是个典型的出列入列嘛!

首先表中有100条数据 user_id=0 对吧? 采用抢占式分配数据,如果你用表锁的话,高并发的话失败成功率太高了。

不如直接把这 user_id=0 的 100条 id 放入 redis list,通过 push pop 的方式来分配数据,这样数据库既没有压力,速度也快很多。只不过需要写一个脚本把这100条 user_id=0 的先入列到 redis

// Redis push
$rows = Code::where('user_id', 0)->get();
$redis = new Redis();
foreach($rows as $row) {
    $redis->rpush('user_id_0_queue', $row->id);
}
// Redis pop
if($id = $redis->lpop('user_id_0_queue')) {
    Code::where('id', $id)->update(['user_id' => Auth::id()]);
} else {
    return '号都发完啦!';
}
1年前 评论
MArtian (作者) 1年前
随波逐流 1年前
kis龍 1年前
yyy123456 1年前
UpGod (楼主) 1年前

在 MySQL 中实现同时将 100 条数据分给 100 个不同的人,需要解决并发问题,防止两个或多个用户同时修改同一条数据,导致数据不一致。下面是一种可能的解决方案:

  • 查询出 user_id=0 的前 100 条数据,使用 SELECT FOR UPDATE 查询锁定这些数据,锁定这些数据可以避免其他人同时修改同一条数据。

  • 将这些数据分成 100 组,每组有一条数据,分给不同的人处理,通过使用 MySQL 事务,确保这些修改操作是原子性的,要么全部成功要么全部失败,避免数据不一致。

下面是示例代码:

BEGIN;
SELECT id FROM code WHERE user_id=0 LIMIT 100 FOR UPDATE;
UPDATE code SET user_id=1 WHERE id IN (1, 2, 3, ..., 100);
COMMIT;

其中 SELECT ... FOR UPDATE 语句会锁定查询结果,防止其他人同时修改数据。UPDATE 语句会将这些数据的 user_id 修改为 1,表示这些数据已经被处理。如果在修改数据时发生了错误,事务会回滚,恢复数据到修改之前的状态

1年前 评论
jiangjun

直接用这个sql呢, UPDATE code set user_id = ? where user_id = 0 limit 1

1年前 评论
MArtian 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!