Symfony2:交易失败,“没有活动交易”。

Posted

技术标签:

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

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

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

一般的代码是:

// ...
$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() 就可以了。 【参考方案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;


【讨论】:

以上是关于Symfony2:交易失败,“没有活动交易”。的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2 - 表单集合 delete_empty 失败

Symfony2 - 学说:模式:更新失败,实体在包之外(解耦)

Symfony2 - 奏鸣曲 Datagrid 过滤器操作符转换为教义_orm_class 字段失败

使用 symfony2 缓存 ReadOnly 学说 2 实体的结果

Symfony:身份验证请求失败:无效的 CSRF 令牌

获取美元交易对的价值