如何使用Doctrine在死锁后重试事务?

Ror*_*ckh 7 php mysql database deadlock doctrine-orm

我正在编写一个PHP函数,它将大量数据存储/更新到表中,这可能会导致死锁.我试图调查如何使用Doctrine重试失败的事务,但遗憾的是无法在线查找任何信息.我最终写了下面的代码

 $retry = 0;
 $done = false;
 while (!$done and $retry < 3) {
     try {

         $this->entityManager->flush();
         $done = true;

     } catch (\Exception $e) {
         sleep(1);

         $retry++;
     }
 }

 if ($retry == 3) {
     throw new Exception(
         "[Exception: MySQL Deadlock] Too many people accessing the server at the same time. Try again in few minutes"
     );
 }
Run Code Online (Sandbox Code Playgroud)

我的问题:这种方法是否有可能在数据库中插入重复项?如果是这样,我怎么能强迫Doctrine回滚交易呢?

hen*_*ngs 14

死锁返回错误1213,您应该在客户端处理该错误

请注意,死锁和锁定等待是不同的事情.陷入僵局,没有"失败"的交易:他们都有罪.无法保证哪一个将被回滚.

您必须使用rollback,您的样式代码将插入重复.例如你应该:

$retry = 0;

$done = false;


$this->entityManager->getConnection()->beginTransaction(); // suspend auto-commit

while (!$done and $retry < 3) {

    try {

        $this->entityManager->flush();

        $this->entityManager->getConnection()->commit(); // commit if succesfull

        $done = true;

    } catch (\Exception $e) {

        $this->entityManager->getConnection()->rollback(); // transaction marked for rollback only

        $retry++;

    }

}
Run Code Online (Sandbox Code Playgroud)

希望这有帮助.

  • 实际上,这不再是真的,因为在异常`EntityManager`进入关闭状态的情况下,它将抛出一个'ORMException`,表明实体管理器在第二次尝试时关闭.学说2.4版.* (21认同)
  • Doctrine 2.6.*+ 有一个 `\Doctrine\DBAL\Exception\RetryableException` 异常,它捕获 `Doctrine\DBAL\Exception\DeadlockException` 和 `Doctrine\DBAL\Exception\LockWaitTimeoutException`。[此处的文档](https://www.doctrine-project.org/projects/doctrine-dbal/en/2.9/reference/transactions.html#error-handling)我建议捕获这些异常(根据您的版本)而不是一个一般的。 (2认同)