【问题标题】:Symfony2: transactions fail with "There is no active transaction."Symfony2:交易失败,“没有活动交易”。
【发布时间】:2015-08-27 12:01:49
【问题描述】:

我花了几个小时试图解决这个问题。谷歌和 Stackoverflow 也没有多大帮助。因此,这里欢迎任何建议。

我正在尝试在更新两个相关表时对事务应用回滚逻辑:

一般的代码是:

// ...
$em = $this->getDoctrine()->getEntityManager();
$em->getConnection()->beginTransaction();

foreach($dataArr as $data) {
    $userObj = $em->getRepository('AcmeBundle:User')->find($userId);
    $userObj->setActive(1);
    $em->persist($userObj);
    $em->getConnection()->commit();
}

$storeObj = $em->getRepository('AcmeBundle:Store')->find($storeId);
$storeObj->setIsOpen(1);
$em->persist($storeObj);
$em->getConnection()->commit();

try {

    $em->flush();
    $em->clear();    

} catch(Exception $e) {

    $em->getConnection()->rollback();
    $em->close();
    throw $e;

}

我的 PDO 驱动程序已启用,没有事务的更新按预期工作,但是一旦我 beginTransaction() 并尝试 commit() 没有任何工作,我得到 There is no active transaction. 异常。

一些消息来源建议只使用 commit() 而不使用 persist() ,但它没有任何区别。我可能在这里做了一些非常愚蠢的事情,但我就是看不到它是什么。

【问题讨论】:

  • 我相信你需要在提交之前刷新,因为提交是在数据库级别,除了标记实体在下一次刷新时持久化之外,persist 并没有真正做任何事情,而刷新实际上执行查询,并且您必须先执行某种查询,然后才能提交。
  • @prodigitalson 你说的完全正确:我从 foreach 循环中删除了 $em->getConnection()->commit(),然后就在 $em->flush() 之前使用了它。现在就像一个魅力。谢谢!
  • 嗯,要么你的解决方案出错,要么我错了。我的建议是刷新,然后提交。就我认为的问题而言,您解决的问题与您的初始代码略有不同。如果您发布的内容有效,那么它一定是您拥有的多个提交语句,因为那是本质上的变化。
  • 另外你不应该用答案来修改你的问题......你可以回答你自己的问题,尽管在你可以将它标记为接受的答案之前有一个等待期。
  • @prodigitalson 我将解决方案移至自己的答案,谢谢。但实际上,一旦我删除了在persist() 之后的commits() 并且在flush() 之前只使用了一个commit() 就可以了。

标签: symfony pdo transactions doctrine rollback


【解决方案1】:

之后

$this->em->getConnection()->beginTransaction(); 

你必须写:

$this->em->getConnection()->setAutoCommit(false);

它对我有用:)

【讨论】:

    【解决方案2】:

    我曾经不小心遇到了这个错误 通过执行以下操作:

    $em->getConnection()->beginTransaction();
    try {
        $em->persist($entityA);
        $em->flush();
    
        $em->persist($entityB);
        $em->flush();
    
        $em->getConnection()->commit();
        //exception thrown here
        $mailer->send($from, $to, $subject, $text);
    } catch (\Exception($ex)) {
        $em->getConnection()->rollback();
    }
    

    所以,您已经猜到,在提交之后不应该有任何代码,因为这个任意代码(在我们的示例中为 $mailer 服务)抛出异常事务将在执行 catch 块之前关闭。也许这会为某人节省一两分钟:)

    【讨论】:

      【解决方案3】:

      DoctrineBundle 1.5.2 版本开始,您可以在项目配置中配置连接以使用auto_commit

      # app/config/config.yml (sf2-3) or config/doctrine.yaml (sf4)
      doctrine:
          dbal:
              auto_commit: false
      

      【讨论】:

      • 不幸的是,这阻止了我的数据装置被刷新到数据库。
      【解决方案4】:

      正如@prodigitalson 正确建议的那样,我需要在flush() 之前执行commit() 才能执行查询。所以现在的工作代码是:

      $em = $this->getDoctrine()->getEntityManager();
      $em->getConnection()->beginTransaction();
      
      foreach($dataArr as $data) {
          $userObj = $em->getRepository('AcmeBundle:User')->find($userId);
          $userObj->setActive(1);
          $em->persist($userObj);
          // this is no longer needed
          // $em->getConnection()->commit();
      }
      
      $storeObj = $em->getRepository('AcmeBundle:Store')->find($storeId);
      $storeObj->setIsOpen(1);
      $em->persist($storeObj);
      // this is no longer needed
      // $em->getConnection()->commit();
      
      try {
      
          // Do a commit before the FLUSH
          $em->getConnection()->commit();
          $em->flush();
          $em->clear();    
      
      } catch(Exception $e) {
      
          $em->getConnection()->rollback();
          $em->close();
          throw $e;
      
      }
      

      【讨论】:

        猜你喜欢
        • 2021-05-11
        • 1970-01-01
        • 2014-04-09
        • 2016-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多