为啥在数据库队列中也会发生数据库脏写?


最后一条的金额,很明显是错了。


我这里的图片,是有做一下悲观锁的,但我刚开始是没有。也就是说出错的时候是没有用lockForUpdate

因为记录是在队列里面一条一条执行的,我觉得是可以不需要使用锁的,加了我反而才觉得多余

你们怎么理解这一现像

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 12

我说下我的理解哈 ,没加锁当然会有并发问题,很简单就可以想 我一个队列跑的时候还没到下面save()逻辑,
file,加上你这里还有一个外部的网络IO,此时我再一个队列进来,读取的余额当然是一样的,而且你这个锁,如果数据库层面没有设置字段不能为负数,会出现并发扣款余额为负数的情况。再多说一句,这根本不叫脏写。

3年前 评论
giao哥

你可以看下队列任务是否存在多次投递

3年前 评论

@Remember 一个队列还没跑完,他不应该是新的队列还没进来吗

3年前 评论
Remember 3年前
深蓝色 (作者) (楼主) 3年前
深蓝色 (作者) (楼主) 3年前
深蓝色 (作者) (楼主) 3年前
深蓝色 (作者) (楼主) 3年前
Remember 3年前
深蓝色 (作者) (楼主) 3年前
深蓝色 (作者) (楼主) 3年前

当两个事务同时尝试去更新某一条数据记录时,就肯定会存在一个先一个后。而当事务A更新时,事务A还没提交,事务B就也过来进行更新,覆盖了事务A提交的更新数据,这就是脏写。

其实就是同一个队列,但发生了两个事务,这其实就是脏写。我觉得我说的没错

3年前 评论

@深蓝色 引用你上面的话:

而当事务 A 更新时,事务 A 还没提交,事务 B 就也过来进行更新,

如果是 innodb,版本不是很老的话,默认的隔离级别都是可重复读,你可以自己查看,可重复读在更新的时候,读取的是当前读,不存在脏写。

3年前 评论

@xh 两个进程同时执行一个队列倒是有可能,但是我是用supervsior去弄的,应该不会重复执行

3年前 评论

看一下你的 supervsior 配置 numprocs 是否大于 1, 这类事务可以用一个独立的队列分类分发, 同类型只分发到这一个队列, 只开一个进程处理, 切勿多开.

你的问题出在于

// 假设你的代码有四个队列任务, 依次投入
job1-> job2-> job3-> job4 -> job5
// 用 supervsior  多进程执行, 比如三个进程
// laralve 保证不重复消费,只是针对 job 不会被重复消费, 里面的代码需要你自己操控
// 那个 queue 能分到的任务多,取决于哪个先执行完成
queue1 = job1
queue2 = job2 -> job4
queue3 = job3 -> job5
  • 看了上面的例子, 如果你开了多进程消费, 就应该能知道为什么会出现你那个情况了
3年前 评论

@深蓝色 请教下为啥用supervsior 监听进程 就不会出现这个问题啊

3年前 评论

@seth-shi 这是干货,不过目前确实是1

3年前 评论

@dalang 如果用supervisor他应该是一个进程的,如果不用supervisor,有可能是把命令设置为背景执行,同时有多个命令在跑

3年前 评论

@深蓝色 1. 附上你的supervisor配置截图, 2. supervisorctl status附上最开始启动的截图, 有进程数量显示

  1. 你的代码, 1s 内处理了 4 个事务,我是不太相信没有多进程同时处理的,纳入 http 请求都不太可能.
3年前 评论

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