EntityManagerclosures

[Doctrine\ORM\ORMException] The EntityManager is closed. 

插入数据后,我得到一个DBALexception后,EntityManagerclosures,我无法重新连接。

我试过这样但是没有得到连接。

 $this->em->close(); $this->set('doctrine.orm.entity_manager', null); $this->set('doctrine.orm.default_entity_manager', null); $this->get('doctrine')->resetEntityManager(); $this->em = $this->get('doctrine')->getEntityManager(); 

任何人有一个想法如何重新连接?

这是一个非常棘手的问题,至less对于Symfony 2.0和Doctrine 2.1来说,在closuresEntityManager之后,不可能以任何方式重新打开它。

我发现克服这个问题的唯一方法是创build你自己的DBAL连接类,包装一个Doctrine并提供exception处理(例如,在将exception向EntityManager中popup之前重试几次)。 这有点怪异,我担心它会导致事务环境中的一些不一致(即,如果失败的查询处于事务中间,我不确定会发生什么)。

一个示例configuration去这种方式是:

 doctrine: dbal: default_connection: default connections: default: driver: %database_driver% host: %database_host% user: %database_user% password: %database_password% charset: %database_charset% wrapper_class: Your\DBAL\ReopeningConnectionWrapper 

class级应该多多lessless地像这样开始:

 namespace Your\DBAL; class ReopeningConnectionWrapper extends Doctrine\DBAL\Connection { // ... } 

一个非常恼人的事情是,你必须重写每个连接方法提供你的exception处理包装。 使用闭包可以缓解一些痛苦。

我的解决scheme

在做任何事之前检查:

 if (!$this->entityManager->isOpen()) { $this->entityManager = $this->entityManager->create( $this->entityManager->getConnection(), $this->entityManager->getConfiguration() ); } 

所有实体将被保存。 但是对于特定的类或者某些情况来说,这是很方便的。 如果你有注入entitymanager一些服务,它仍然是封闭的。

Symfony 2.0

 $em = $this->getDoctrine()->resetEntityManager(); 

Symfony 2.1+

 $em = $this->getDoctrine()->resetManager(); 

你可以重置你的EM

 // reset the EM and all aias $container = $this->container; $container->set('doctrine.orm.entity_manager', null); $container->set('doctrine.orm.default_entity_manager', null); // get a fresh EM $em = $this->getDoctrine()->getManager(); 

这就是我如何解决“EntityManagerclosures”的原则 问题。 基本上每次有一个例外(即重复键)主义closures实体pipe理器。 如果您仍想与数据库交互,则必须通过调用resetManager()提到的resetManager()方法来重置实体pipe理器

在我的应用程序中,我运行着多个RabbitMQ使用者,他们都在做同样的事情:检查数据库中是否存在实体,如果是,则返回它,如果没有创build并返回。 在检查该实体是否已经存在并创build它之间的几毫秒之间发生了同样的事情,并创build了丢失的实体,使得另一个消费者产生重复密钥exception。

这导致了软件devise问题。 基本上我试图做的是在一个事务中创build所有的实体。 这可能对大多数人来说很自然,但在我的情况下在概念上是绝对错误的。 考虑以下问题:我必须存储一个具有这些依赖性的足球比赛实体。

  • 一组(即A组,B组…)
  • 一轮(即半决赛)
  • 比赛场地(比赛场地)
  • 比赛状态(即半场,全场)
  • 两队打比赛
  • 比赛本身

现在,为什么会场创作应该和比赛一样? 这可能是因为我刚刚收到一个新的场所,它不在我的数据库中,所以我必须先创build它。 但也可能是这个场地可能会举办另一场比赛,所以另一个消费者可能会同时尝试创造它。 所以我所要做的就是首先在单独的事务中创build所有的依赖关系,确保我重置了一个重复键exception的实体pipe理器。 我想说,比赛旁边的所有实体都可以定义为“共享”,因为它们可能是其他消费者中其他交易的一部分。 在这里不“共享”的东西是匹配本身,而这种匹配本身不可能同时由两个消费者创build。 所以在最后的交易中,我希望看到两队之间的比赛和关系。 所有这一切也导致了另一个问题。 如果您重置实体pipe理器,重置之前您检索的所有对象都是全新的。 所以教义不会试图对他们运行一个更新 ,而是一个INSERT ! 因此,请确保在逻辑上正确的事务中创build所有依赖关系,然后在将所有对象设置为目标实体之前,从数据库中检索所有对象。 以下面的代码为例:

 $group = $this->createGroupIfDoesNotExist($groupData); $match->setGroup($group); // this is NOT OK! $venue = $this->createVenueIfDoesNotExist($venueData); $round = $this->createRoundIfDoesNotExist($roundData); /** * If the venue creation generates a duplicate key exception * we are forced to reset the entity manager in order to proceed * with the round creation and so we'll loose the group reference. * Meaning that Doctrine will try to persist the group as new even * if it's already there in the database. */ 

所以这就是我认为应该做的。

 $group = $this->createGroupIfDoesNotExist($groupData); // first transaction, reset if duplicated $venue = $this->createVenueIfDoesNotExist($venueData); // second transaction, reset if duplicated $round = $this->createRoundIfDoesNotExist($roundData); // third transaction, reset if duplicated // we fetch all the entities back directly from the database $group = $this->getGroup($groupData); $venue = $this->getVenue($venueData); $round = $this->getGroup($roundData); // we finally set them now that no exceptions are going to happen $match->setGroup($group); $match->setVenue($venue); $match->setRound($round); // match and teams relation... $matchTeamHome = new MatchTeam(); $matchTeamHome->setMatch($match); $matchTeamHome->setTeam($teamHome); $matchTeamAway = new MatchTeam(); $matchTeamAway->setMatch($match); $matchTeamAway->setTeam($teamAway); $match->addMatchTeam($matchTeamHome); $match->addMatchTeam($matchTeamAway); // last transaction! $em->persist($match); $em->persist($matchTeamHome); $em->persist($matchTeamAway); $em->flush(); 

我希望它有助于:)

在控制器中。

exceptionclosures实体pipe理器。 这使批量插入的麻烦。 要继续,需要重新定义它。

 /** * @var \Doctrine\ORM\EntityManager */ $em = $this->getDoctrine()->getManager(); foreach($to_insert AS $data) { if(!$em->isOpen()) { $this->getDoctrine()->resetManager(); $em = $this->getDoctrine()->getManager(); } $entity = new \Entity(); $entity->setUniqueNumber($data['number']); $em->persist($entity); try { $em->flush(); $counter++; } catch(\Doctrine\DBAL\DBALException $e) { if($e->getPrevious()->getCode() != '23000') { /** * if its not the error code for a duplicate key * value then rethrow the exception */ throw $e; } else { $duplication++; } } } 

尝试使用:

 $em->getConnection()->[setNestTransactionsWithSavepoints][1](true); 

在开始交易之前。

Connection::rollback方法上,它检查nestTransactionsWithSavepoints属性。

这真是个老问题,但我也有类似的问题。 我正在做这样的事情:

 // entity $entityOne = $this->em->find(Parent::class, 1); // do something on other entites (SomeEntityClass) $this->em->persist($entity); $this->em->flush(); $this->em->clear(); // and at end I was trying to save changes to first one by $this->em->persist($entityOne); $this->em->flush(); $this->em->clear(); 

问题是,清除所有的实体,包括第一个抛出错误EntityManagerclosures。

在我的情况下, 解决scheme只是清除不同types的实体,并将$entityOne留在EM下:

 $this->em->clear(SomeEntityClass::class); 
 // first need to reset current manager $em->resetManager(); // and then get new $em = $this->getContainer()->get("doctrine"); // or in this way, depending of your environment: $em = $this->getDoctrine(); 

我有这个问题。 我如何修复它。

尝试刷新或持续时,连接似乎closures。 试图重新开放是一个不好的select,因为会产生新的问题。 我尝试了解为什么连接被closures,并发现我坚持之前做了太多的修改。

坚持()早些时候解决了这个问题。

我面临同样的问题。 在这里看几个地方是我如何处理它。

 //function in some model/utility function someFunction($em){ try{ //code which may throw exception and lead to closing of entity manager } catch(Exception $e){ //handle exception return false; } return true; } //in controller assuming entity manager is in $this->em $result = someFunction($this->em); if(!$result){ $this->getDoctrine()->resetEntityManager(); $this->em = $this->getDoctrine()->getManager(); } 

希望这可以帮助别人!