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(); }
希望这可以帮助别人!