记一次 Laravel MySQL 验证出 bug 的经历
- 本人之前做了一个简单的会议预约系统
- 逻辑非常的简单
- 建立用户占用时间表
used_time
- 和会议预约表
meeting_books
- 规定会议时间以半小时为单位,最长不得超过两个小时
- 用户每预定一个时间我就会向占用时间表里插入时间
- 比如预定
08:00~09:00
我就会向占用时间表插入08:00
和08:30
08:00
和08:30
代表的是时间段的含义,是08:00~08:30
和08:30~09:00
的意思
预约创建的逻辑是
- 在占用时间表,验证请求时间是否被占用,没有则进行第2步,有则返回失败
- 创建预约,并将请求写入操作日志
- 向占用时间表插入数据
- 假设用户选中
2018-08-30 08:00~09:00
的时间在一号会议室开会
- 在创建订单的时候我会先从占用时间表
used_time
查找一号会议室 2018-08-30
里有没有08:00
和08:30
- 如果有返回时间已被占用,创建失败
- 没有就创建预约,并纪录日志
- 然后再占用时间表里插入
一号会议室 2018-08-30
的08:00
和08:30
时间段 - 最后返回
201
给前端
出现的问题
- 但有一次出现了一个bug,一个用户再同一天同一个时间段创建了两个请求
- 我当时很困惑,这个用户是怎么通过前端验证和后端验证的
- 于是私聊她,她说是第一个请求时出现
error
提示她失败 - 于是她又重新立马创建了一个
- 但是最后两个请求都成功了
伪代码逻辑
- 这里为什么
create
后findOrFail
,是因为create
返回的是创建实例,而不是所有数据,我日志需要纪录所有数据
//创建数据
$meeting = meeting::create($data);
//查询数据
$meeting = meeting::findOrFail($meeting->id);
//纪录操作日志
Log::insert($meeting);
.......
//占用时间表插入
usedTime::insert($data);
问题出现的原因
- 通过这番调查我大概明白了问题出现的原因
- 线上数据库是读写分离的,主库写入,但更新数据后马上查询,从库可能没来得及更新数据
- 当网络不好时遇到从库更新不及时
findOrFail
就会报404
,导致后面所有操作都失效,自然验证也失效了
解决方法
- 更新完后,查询指定使用主库
- 更新后
禁止查询
,直接使用create
返回的model
实例,对于数据库中的有默认值的字段,手动加入到model
实例中
本作品采用《CC 协议》,转载必须注明作者和本文链接
这个配置有设置过吗?
@baiachen 这配置的作用是什么呢?
@Aaron
sticky
是一个 可选值,它可用于立即读取在当前请求周期内已写入数据库的记录。若sticky
被启用,并且当前请求周期内执行过「写」操作,那么任何「读」操作都将使用「写」连接。这样可确保同一周期内写入的数据在同一周期内都可以被立即读取。它是否启用,取决于应用程序的需求@baiachen 谢谢
@baiachen 学习了