我有一个Symfony应用程序,它公开了一组JSON Web服务,供移动应用程序使用。
在过去的几天里,我们有很多并发用户使用该应用程序(每天约5000次访问),并且我的日志中开始“随机”出现Doctrine错误。它每天大约出现2-3次,并且这是错误信息:
在过去的几天里,我们有很多并发用户使用该应用程序(每天约5000次访问),并且我的日志中开始“随机”出现Doctrine错误。它每天大约出现2-3次,并且这是错误信息:
Uncaught PHP Exception Doctrine\DBAL\Exception\DriverException: "An exception occurred while executing 'UPDATE fos_user_user SET current_crystals = ?, max_crystals = ?, updated_at = ? WHERE id = ?' with params [31, 34, "2017-12-19 09:31:18", 807]:
SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction" at /var/www/html/rollinz_cms/releases/98/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php line 115
在更新用户表时似乎无法获取锁定。控制器代码如下:
/**
* @Rest\Post("/api/badges/{id}/achieve", name="api_achieve_badge")
*/
public function achieveAction(Badge $badge = null)
{
if (!$badge) {
throw new NotFoundHttpException('Badge not found.');
}
$user = $this->getUser();
$em = $this->getDoctrine()->getManager();
$userBadge = $em->getRepository('AppBundle:UserBadge')->findBy(array(
'user' => $user,
'badge' => $badge,
));
if ($userBadge) {
throw new BadRequestHttpException('Badge already achieved.');
}
$userBadge = new UserBadge();
$userBadge
->setUser($user)
->setBadge($badge)
->setAchievedAt(new \DateTime())
;
$em->persist($userBadge);
// sets the rewards
$user->addCrystals($badge->getCrystals());
$em->flush();
return new ApiResponse(ApiResponse::STATUS_SUCCESS, array(
'current_crystals' => $user->getCurrentCrystals(),
'max_crystals' => $user->getMaxCrystals(),
));
}
我查阅了MySQL和Doctrine文档,但没有找到可靠的解决方案。Doctrine建议重试事务,但没有给出实际例子:
https://dev.mysql.com/doc/refman/5.7/en/innodb-deadlock-example.html
try {
// process stuff
} catch (\Doctrine\DBAL\Exception\RetryableException $e) {
// retry the processing
}
这篇文章建议重试事务,我该怎么做?
可能是服务器问题(访问过多),我必须提升服务器性能,还是代码有问题,我必须在代码中明确处理死锁?
RetryableException
类。我甚至更新了我的doctrine/orm版本。我需要安装特定的composer包吗? - StockBreakThe EntityManager is closed
,我需要在 flush 之前调用$this->getDoctrine()->resetManager();
和$em = $this->getDoctrine()->getManager();
吗? - StockBreak