并发实际开发案例
1.案例
在score 积分表内,每次新增任务都会把之前任务的 score 分数累加,计算总积分 all_score
// score 表结构
CREATE TABLE `score` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL COMMENT '用户ID',
`task_id` int(11) DEFAULT NULL COMMENT '任务ID',
`score` bigint(11) DEFAULT NULL COMMENT '任务积分',
`all_score` bigint(11) DEFAULT NULL COMMENT '总积分',
`status` tinyint(1) DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
一般正常逻辑
// 查询所有任务积分
select sum(score) from score where user_id = 1;
// 将任务积分添加至总积分中
insert into score ...
如果没有并发处理,同时有多个会话插入任务时
在计算总分时会出现错误
2.解决
使用事务,增加排他锁写锁,短暂的阻塞其他会话的执行
$this->start();
try{
$sql = "select sum(score) from score where uid = 1 for update";
$sql = "inster into ...";
$this->commit();
}catch(Exception $exception){
$this->rollback();
return $exception->getMessage();
}
3.场景分析
-
for update
禁止其他事务在这些加了锁的行上进行操作
使用 for update 推演过程:
时间 | 会话 1 | 会话 2 |
---|---|---|
1 | select sum(score) from score where uid = 1 for update | |
2 | 插入数据 inster into ... | select sum(score) from score where uid = 1 for update |
3 | 事务提交 | 等待会话 1 释放写锁 |
4 | 插入数据 inster into ... | |
5 | 事务提交 |
-
lock in share mode
在读取到的行上设置共享锁,其他会话可以读取行,也可以继续给行加共享锁,但是在当前事务提交之前其他会话不能修改加了共享锁的行
如果这些行被尚未提交的,另一个事务更改
则当前查询将等待直到该事务结束,然后使用最新值
使用 lock in share mode 推演过程:
时间 | 会话 1 | 会话 2 |
---|---|---|
1 | select sum(score) from score where uid = 1 lock in share mode | |
2 | 插入数据 inster into ... | select sum(score) from score where uid = 1 lock in share mode |
3 | 等待会话2释放读锁 | 插入数据 inster into ... |
4 | 继续等待 | 检测死锁 |
5 | 继续等待 | 回滚事务 |
6 | 事务提交 |
如果使用上述场景下会造成死锁
lock in share mode 的应用场景适合于两张表存在关系时的写操作
假如存在两张有关系的表:PARENT和CHILD
使用SELECT语句(快照读)来查询表PARENT并验证父行是否存在,后再将子行插入CHILD表
可能其他的会话会删除父行
我们使用加共享锁的方式执行
SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;
就可以安全地将子记录添加到CHILD表中并提交事务。
其他会话都将等到你完成操作提交事务后再进行
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律