对于我们使用Laravel编写的Web应用程序,我们使用事务来更新数据库。我们已经将数据分成了不同的数据库(为了方便起见,让我们说" app""用户")。在应用程序更新期间,会触发事件以更新用户数据库中的某些用户统计信息。但是,此应用程序更新可能会作为应用程序数据库上事务的一部分进行调用,因此代码结构如下所示。
DB::connection('app')->beginTransaction();
// ...
DB::connection('user')->doStuff();
// ...
DB::connection('app')->commit();
在游戏事务中,任何尝试在用户连接上启动事务(因为单个查询已创建隐式事务)都不起作用,从而导致死锁(请参阅InnoDB status output)。我还使用innotop来获取更多信息,但是当它显示锁等待时,它没有显示它被阻止的查询。用户桌上有一个锁,但我找不到它的来源。相关输出如下所示:
简单的解决方案是从事务中提取用户操作,但由于实际代码稍微复杂一些(doStuff
实际上发生在事务期间调用的嵌套方法中的某个地方,并且从不同的方法调用地方),这远非微不足道。我非常希望doStuff
成为事务的一部分,但我不知道事务如何跨越多个数据库。
这种情况导致死锁的原因是什么?是否可以在此事务中运行用户数据库上的doStuff
,或者我们是否必须找到一个完全不同的解决方案,例如将事件排队等待执行?
答案 0 :(得分:1)
我找到了一种使用变通方法解决此问题的方法。我的假设是它试图使用app连接来更新用户数据库,但在强制它使用用户连接后,它仍然被锁定。然后我切换它并使用应用程序连接来更新用户数据库。由于我们在数据库之间有连接,因此我们拥有适当访问权限的数据库用户,因此这没有问题。这实际上解决了这个问题。
也就是说,最终的代码就像是
DB::connection('app')->beginTransaction();
// ...
DB::connection('app')->table('user.users')->doStuff(); // Pay attention to this line!
// ...
DB::connection('app')->commit();