Tom*_*Tom 3 php mysql deadlock symfony doctrine-orm
我有一个基于 Symfony 的移动应用程序和服务器,它为移动应用程序提供 API。
我有一种情况,用户可以喜欢Post. 当用户喜欢Post我在 ManyToMany 表中添加这个特定用户喜欢这个特定的条目时Post(步骤 1)。然后在Post表中我增加 likesCounter(步骤 2)。然后在User表中我增加了用户的游戏化点数(因为他喜欢Post)(第 3 步)。
因此,存在许多用户同时喜欢特定Post并且发生死锁(在Post桌子上或User桌子上)的情况。如何处理?在Doctrine Docs 中,我可以看到这样的解决方案:
<?php
try {
// process stuff
} catch (\Doctrine\DBAL\Exception\RetryableException $e) {
// retry the processing
}
Run Code Online (Sandbox Code Playgroud)
但我应该怎么做catch?重试整个点赞过程(步骤 1 到 3),例如 3 次,如果失败,将 BadRequest 返回到移动应用程序?或者是其他东西?
我不知道这是否是一个很好的例子,因为也许我可以尝试重建进程,这样就不会发生死锁,但我想知道如果它们真的发生了我该怎么办?
小智 8
我不同意 Stefan,死锁是正常的,正如 MySQL 文档所说:
通常,您必须编写应用程序,以便它们随时准备在事务因死锁回滚时重新发出事务。
但是,Stefan 建议的循环是正确的解决方案。除了它缺少一个重要的点:在 Doctrine 抛出异常之后,EntityManager 变得不可用,您必须在 catch 子句中使用来自 ManagerRegistry 实例的 resetManager() 创建一个新的。
当我和你有同样的担忧时,我在网上搜索,但没有找到任何完全令人满意的答案。所以我弄脏了我的手,回来了一篇文章,你会发现我上面所说的一个实现示例:
我要做的是将所有喜欢发布到队列中,并使用批处理消费者使用它们,以便您可以将更新分组到单个帖子上。
如果您坚持保持当前的实施,您可以按照您自己建议的方式进行:
<?php
for ($i = 0; $i < $retryCount; $i++) {
try {
// try updating
break;
} catch (\Doctrine\DBAL\Exception\RetryableException $e) {
// you could also add a delay here
continue;
}
}
if ($i === $retryCount) {
// throw BadRequest
}Run Code Online (Sandbox Code Playgroud)
这是一个丑陋的解决方案,我不会建议它。不应该通过重试或使用延迟来“避免”死锁。还要查看命名锁并使用相同的重试系统,但不要等待死锁发生。
| 归档时间: |
|
| 查看次数: |
3599 次 |
| 最近记录: |