重复录入' ...'关键' PRIMARY'在交易期间

时间:2015-09-02 22:30:19

标签: php mysql symfony doctrine-orm transactions

这件事昨晚发生在我身上。我对错误的本质非常熟悉,但我仍然无法弄清楚可能导致错误的原因。我可能有预感,但我不确定。我将从一些基本的应用信息开始:​​

我的应用有3个实体:LoanSystemPageTextPage。每当有人添加贷款时,都会向数据库添加一个或多个系统页面。基本上,它是这样的:

if ( $form->isValid()){
    $this->em->getConnection()->beginTransation();
    $this->em->persist($loan);
    $this->em->flush();

    while ($someCondition){
        $page = new SystemPage();
        //... Fill the necessary data into page
        $page->setObject($loan);
        $this->em->persist($page);
    }

    $this->em->flush();
    $this->em->getConnection()->commit();
}

请忽略潜在的拼写错误,我通过记住

来写字面意思

实体Loan映射到表loansSystemPage映射(通过继承映射)到system_pagesbase_pages。后两者都有id字段,设置为AUTO_INCREMENT

我的预感:还有另一张名为text_pages的桌子。鉴于另一方面text_pagesbase_pages以及另一方<{>> ID 上的system_pagesbase_pages,我认为这很容易导致这种情况:

User1: Create BasePage, acquire autoincrement ID (value = 1)
User2: Create BasePage, acquire autoincrement ID (value = 1)
User1: Create TextPage, use the ID from step 1
User2: Create SystemPage, use the ID from step 2

这个理论存在两个问题:

  • 交易。这就是我在第一时间使用它们的原因
  • 在发生错误时,其他用户没有对其他活动

重要提示:等待一分钟后,重新提交确认。

这可能是一些奇怪的MySQL事务隔离错误吗?任何提示都将不胜感激......

编辑:

DB Schema的一部分:

enter image description here

请忽略塞尔维亚语中的列名

2 个答案:

答案 0 :(得分:1)

flush()操作刷新一个事务中的所有更改,因此这里有冗余代码......

您没有声明是否可以重现此错误,并且如果您可以提供数据库架构将会很方便。

答案 1 :(得分:1)

似乎这个问题没有正确答案,只有猜测,所以我会根据自己的经验提出一些故障排除方法,如下:

  1. 你提到应用程序上没有其他活动,但我会通过查看查询日志来检查它。必须存在重复执行的查询。

  2. 表格可能是两次意外提交的。用户双击提交按钮,或者如果UI没有响应,则再次单击。您可以通过在同一时间戳上查看表单上的POST请求的Apache日志文件来检查这个想法。您可能需要实施一些JavaScript代码,以防止双击您的表单页面提交按钮。

  3. 你的预感可能非常接近正确,因为存在某种竞争条件。使用事务不会阻止竞争条件,但它们确实提供了优雅回滚的方法。将代码包装在try / catch块中,以便捕获Mysql异常并向用户显示友好错误和重试选项。