首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在使用Laravel队列时,如何避免作业DB表锁问题?

在使用Laravel队列时,如何避免作业DB表锁问题?
EN

Stack Overflow用户
提问于 2015-09-09 17:28:29
回答 2查看 6.7K关注 0票数 18

我使用的是Laravel 5.1。

队列用于在多个系统之间获取/同步数据。

我使用数据库驱动程序,3个"artisan queue:work --daemon“进程一直在运行。

作业由系统用户和调度程序(cron)分派。使用三个队列来确定作业的优先级。

一切似乎都运行得很好--作业表中充满了记录,系统会处理这些记录,并删除已完成的记录。

然而,在一段时间后,锁定问题开始干扰:

SQLSTATE40001:序列化失败:尝试获取锁时发现1213死锁;请尝试重新启动事务

'RuntimeException‘并显示消息’Can‘with PDO instance Can transaction.’

SQLSTATEHY000:常规错误: 1205锁定等待超时;请尝试重新启动事务

我还没有尝试使用其他队列驱动程序。不过我真的很想继续使用数据库。引擎是InnoDB,作业表有默认的结构和索引。

有没有办法解决这个问题?你的想法是什么?

值得一提的是,我在作业类中调用DB::reconnect(),因为队列工作进程是作为守护进程运行的。

正如人们所预期的那样,作业使用DispatchesJobs特征进行分派。我不会以任何其他方式干扰队列算法。

EN

回答 2

Stack Overflow用户

发布于 2016-01-13 12:13:07

这可能不是答案,而是一些信息。

在使用SELECT ... FOR UPDATE语句时,您可能会观察到锁争用(死锁等)。

代码语言:javascript
复制
select … for update where x <= y

它使用<=进行范围扫描数据库锁定所有行<= y,包括任何间隙,所以如果您有像这样y的行: 1,3,5,它甚至锁定索引中1和3之间的空白空间这称为间隙锁定

可以看到这个命令的问题:

代码语言:javascript
复制
SHOW ENGINE INNODB STATUS;

---TRANSACTION 72C, ACTIVE 755 sec
4 lock struct(s), heap size 1248, 3 row lock(s), undo log entries 1
MySQL thread id 3, OS thread handle 0x7f84a78ba700, query id 163 localhost msandbox
TABLE LOCK table test.t trx id 72C lock mode IX
RECORD LOCKS space id 19 page no 4 n bits 80 index age of table test.t trx id 72C lock_mode X
RECORD LOCKS space id 19 page no 3 n bits 80 index GEN_CLUST_INDEX of table test.t trx id 72C lock_mode X locks rec but not gap
RECORD LOCKS space id 19 page no 4 n bits 80 index age of table test.t trx id 72C lock_mode X locks gap before rec

最后一行

如果您的事务中有很多影响并发和性能的间隙锁,您可以通过两种不同的方式禁用它们:

代码语言:javascript
复制
1- Change the ISOLATION level to READ COMMITTED. In this isolation level, it is normal and expected that query results can change during a transaction, so there is no need to create locks to prevent that from happening.

2- innodb_locks_unsafe_for_binlog = 1. Disables the gap locks except for foreign-key constraint checking or duplicate-key checking.

https://www.percona.com/blog/2012/03/27/innodbs-gap-locks/

票数 2
EN

Stack Overflow用户

发布于 2019-03-12 23:39:07

我在Laravel上编写队列管理系统,我有多个作业,有多个用户,我应该发送电子邮件。我正在运行许多工人与主管和避免多个电子邮件发送给同一个用户,我写了这段代码。希望它能帮助解决这个问题的人

代码语言:javascript
复制
DB::transaction(function () use ($job) {

            if (!count($job->jobUsers()->sharedLock()->get())) { // to share reading ability btw multiple workers

                Log::info('There is no user in this job');
                $job->status = Job::STATUS_FINISHED;
                $job->save();
                return;

            }

            foreach ($job->jobUsers as $jobUser) {
                Log::info($jobUser->user_id);

                JobUser::where('job_id', $jobUser->job_id)
                    ->where('user_id', $jobUser->user_id)
                    ->lockForUpdate()  // exclusive lock
                    ->update(['status' => JobUser::STATUS_SENT]);
            }

        });
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32475853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档