在多个实体管理器上处理条令事务

Ben*_*der 5 transactions symfony doctrine-orm

如果满足以下条件,则应回滚两个事务:

  1. $em1失败但$em2成功。
  2. $em1成功但$em2失败。

那么,当涉及多个 EM 时,我下面的示例处理交易的方法是否正确?我在阅读事务和并发文档后想出了它。

$em1->getConnection()->beginTransaction();
$em2->getConnection()->beginTransaction();

try {
     $em1->persist($object1);
     $em1->flush();
     $em1->getConnection()->commit();

     $em2->persist($object2);
     $em2->flush();
     $em2->getConnection()->commit();
} catch (Exception $e) {
     $em1->getConnection()->rollback();
     $em2->getConnection()->rollback();
}
Run Code Online (Sandbox Code Playgroud)

我尝试实现这个的原因是因为我....resulted in a Doctrine\ORM\ORMException exception (The EntityManager is closed.)在应用程序中的某个地方遇到了错误。我可能可以用下面的方法来处理它,但我认为使用事务来处理上面的业务逻辑更好。

private function getNewEntityManager($em)
{
    if (!$em->isOpen()) {
        $em = $em->create($em->getConnection(), $em->getConfiguration());
    }

    return $em;
}
Run Code Online (Sandbox Code Playgroud)

小智 1

我想指出几件事可能会让你对这个问题理清思路:

我不知道您用于创建第二个实体管理器的过程,请记住,两个完全不同的实体管理器不会共享相同的连接。您能指出 2 个不同实体管理器的用例吗?

考虑该操作:

$em1->getConnection()->commit();
Run Code Online (Sandbox Code Playgroud)

将提交第一个事务,并且如果第二个事务出现错误,您将失去回滚该事务的权限。


 Doctrine\ORM\ORMException exception (The EntityManager is closed.)
Run Code Online (Sandbox Code Playgroud)

这是典型的,当您在抛出 DBAL(数据库相关)异常后尝试执行任何提交/刷新操作时;在这种情况下,Doctrine 默认行为是关闭实体管理器。在任何回滚之后执行此操作是常见的做法:

$em1->getConnection()->rollback();
$em1->close();
Run Code Online (Sandbox Code Playgroud)

希望它有帮助,问候。