我在日志中看到以下错误。
SQLSTATE[HY000]:一般错误:超过1205锁定等待超时;尝试重新启动事务(SQL:从
job_batches
中选择*,其中id
=xxx限制1用于更新(
我发现这个查询是在Laravel更新数据库中已处理作业数之前进行的。但不知道为什么会发生这种超时(代码在事务中,所以应该立即释放锁(。
附言:我使用亚马逊SQS来驱动我的队列
p.S.S.我建议有一些作业没有提交嵌套的Laravel事务。但我试图重现这样一个场景,看起来这个建议是错误的。
简而言之,这是因为一批中有大量的作业。解决方案是将作业以较小的块添加到批中(使用add()
方法(。
问题的出现是因为一个事务中发生了两件事(参见下面的代码片段(:
- 数据库中更新的作业总数
- 作业被发送到队列(在我的案例中是亚马逊SQS(
关键是,如果有很多作业,第二条语句会花费大量时间。只要执行了,事务就不能提交(并且第一条语句中受影响的行保持锁定(。但是一旦第一个作业被推送到队列,它就会由工作者处理。在处理完作业工作者尝试更新数据库中的行之后,它执行SELECT ... FOR UPDATE
。等待直到发生超时
这是Laravel代码的相应片段:
$this->repository->transaction(function () use ($jobs, $count) {
// Statement 1 (the affected row stays locked until transaction is committed)
$this->repository->incrementTotalJobs($this->id, $count);
// Statement 2 (can take a lot of time)
$this->queue->connection($this->options['connection'] ?? null)->bulk(
$jobs->all(),
$data = '',
$this->options['queue'] ?? null
);
});