[Doctrine\ORM\ORMException]
The EntityManager is closed.
插入数据后出现DBAL异常后,EntityManager关闭,我无法重新连接。
我试过这样但是没有得到联系。
$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();
任何人都知道如何重新连接?
答案 0 :(得分:53)
我的解决方案。
在做任何事情之前检查:
if (!$this->entityManager->isOpen()) {
$this->entityManager = $this->entityManager->create(
$this->entityManager->getConnection(),
$this->entityManager->getConfiguration()
);
}
将保存所有实体。但它对特定类或某些情况很方便。如果你有一些注入了entitymanager的服务,它仍然会被关闭。
答案 1 :(得分:31)
Symfony 2.0 :
$em = $this->getDoctrine()->resetEntityManager();
Symfony 2.1 + :
$em = $this->getDoctrine()->resetManager();
答案 2 :(得分:24)
这是一个非常棘手的问题,因为至少对于Symfony 2.0和Doctrine 2.1来说,在关闭后不可能以任何方式重新打开EntityManager。
我发现克服此问题的唯一方法是创建自己的DBAL Connection类,包装Doctrine并提供异常处理(例如,在将异常弹出到EntityManager之前重试几次)。它有点hacky,我担心它会导致事务环境中的一些不一致(即,我不确定如果失败的查询处于事务中间会发生什么)。
采用这种方式的示例配置是:
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
课程应该或多或少地开始:
namespace Your\DBAL;
class ReopeningConnectionWrapper extends Doctrine\DBAL\Connection {
// ...
}
一个非常烦人的事情是你必须覆盖提供异常处理包装的Connection的每个方法。使用闭合可以减轻那里的痛苦。
答案 3 :(得分:17)
您可以重置您的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();
答案 4 :(得分:17)
这就是我解决Doctrine " EntityManager已关闭的问题。" 问题。
基本上每次出现异常(即重复密钥)时,Doctrine都会关闭实体管理器。如果您仍想与数据库进行交互,则必须通过调用 JGrinon 所提及的resetManager()
方法来重置实体管理器。
在我的应用程序中,我运行了多个RabbitMQ使用者,他们都在做同样的事情:检查数据库中是否存在实体,如果是,则返回它,如果不创建它然后返回它。 在检查该实体是否已经存在并创建它之间的几毫秒内,另一个消费者碰巧做了同样的事情并创建了丢失的实体,使另一个消费者出现了重复的密钥异常。
这导致了软件设计问题。基本上我想要做的是在一个事务中创建所有实体。这对大多数人来说可能是自然的,但在我的情况下肯定是概念错误的。考虑以下问题:我必须存储具有这些依赖关系的足球比赛实体。
现在,为什么场地创建应该与匹配在同一个交易中?可能是因为我刚刚收到一个新的地点而不在我的数据库中,所以我必须先创建它。但也可能是该场地可能会举办另一场比赛,因此另一位消费者可能会尝试同时创建它。所以我要做的是首先在单独的事务中创建所有依赖项,确保我在重复键异常中重置实体管理器。我要说匹配旁边的所有实体都可以定义为"共享"因为它们可能是其他消费者中其他交易的一部分。没有"共享的东西"在那里,匹配本身不可能同时由两个消费者创造。所以在上一次交易中,我希望看到比赛以及两支球队和比赛之间的关系。所有这些都导致了另一个问题。如果重置实体管理器,则在重置之前检索的所有对象都是全新的Doctrine。因此,Doctrine不会尝试在它们上运行 UPDATE ,而是 INSERT !因此,请确保在逻辑上正确的事务中创建所有依赖项,然后在将它们设置为目标实体之前从数据库中检索所有对象。请考虑以下代码作为示例:
$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();
我希望它有所帮助:)
答案 5 :(得分:4)
在控制器中。
异常关闭实体管理器。这会导致批量插入的麻烦。 要继续,需要重新定义它。
/**
* @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++;
}
}
}
答案 6 :(得分:2)
我觉得这是值得的,因为在try / catch循环中捕获了我没有做任何事情的SQL错误(带有em->flush()
),这在批处理导入命令中发生了。就我而言,这是因为我试图插入一条记录,该记录的非空属性保留为null。
通常,这将导致发生严重异常,并且命令或控制器停止运行,但是我只是记录此问题并继续进行。 SQL错误导致实体管理器关闭。
请检查您的dev.log
文件中是否存在此类愚蠢的SQL错误,因为这可能是您的错。 :)
答案 7 :(得分:1)
尝试使用:
$em->getConnection()->[setNestTransactionsWithSavepoints][1](true);
开始交易之前。
在Connection::rollback
方法上,它会检查nestTransactionsWithSavepoints
属性。
答案 8 :(得分:0)
这是一个很老的问题,但我遇到了类似的问题。我正在做这样的事情:
// 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();
问题在于明确分离所有实体,包括第一个实体和抛出错误 EntityManager已关闭。
在我的情况下,解决方案只是明确了不同类型的实体并让$entityOne
仍在EM下:
$this->em->clear(SomeEntityClass::class);
答案 9 :(得分:0)
这是你如何在 Symfony3 中重置 entityManager。如果它已经关闭,它应该重新打开 em:
在控制器中:
$em = $this->getDoctrine()->resetEntityManager();
在服务中:
if (!$this->em->isOpen()) {
$this->managerRegistry->resetManager('managername');
$this->em = $this->managerRegistry->getManager('default');
}
$this->em->persist(...);
不要忘记在 service.yml 中注入“@doctrine”作为服务参数!
我想知道,如果不同的方法同时尝试同时访问同一个实体,是否会出现这个问题?
答案 10 :(得分:0)
相同的问题,可以通过简单的代码重构来解决。 当必填字段为null时,有时会出现问题,然后再尝试重构代码。更好的工作流程可以解决问题。
答案 11 :(得分:0)
在测试Symfony 4.3.2的更改时遇到了相同的问题
我将日志级别降低到INFO
然后再次运行测试
日志记录显示:
console.ERROR: Error thrown while running command "doctrine:schema:create". Message: "[Semantical Error] The annotation "@ORM\Id" in property App\Entity\Common::$id was never imported. Did you maybe forget to add a "use" statement for this annotation?" {"exception":"[object] (Doctrine\\Common\\Annotations\\AnnotationException(code: 0): [Semantical Error] The annotation \"@ORM\\Id\" in property App\\Entity\\Common::$id was never imported. Did you maybe forget to add a \"use\" statement for this annotation? at C:\\xampp\\htdocs\\dirty7s\\vendor\\doctrine\\annotations\\lib\\Doctrine\\Common\\Annotations\\AnnotationException.php:54)","command":"doctrine:schema:create","message":"[Semantical Error] The annotation \"@ORM\\Id\" in property App\\Entity\\Common::$id was never imported. Did you maybe forget to add a \"use\" statement for this annotation?"} []
这意味着代码中的某些错误导致:
Doctrine\ORM\ORMException: The EntityManager is closed.
所以检查日志是个好主意
答案 12 :(得分:0)
在 Symfony 4.2 + 中,您必须使用该软件包:
composer require symfony/proxy-manager-bridge
否则您将获得例外:
Resetting a non-lazy manager service is not supported. Declare the "doctrine.orm.default_entity_manager" service as lazy.
比您可以像这样重置entityManager:
services.yaml:
App\Foo:
- '@doctrine.orm.entity_manager'
- '@doctrine'
Foo.php:
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\DBAL\DBALException;
use Doctrine\ORM\EntityManagerInterface;
try {
$this->entityManager->persist($entity);
$this->entityManager->flush();
} catch (DBALException $e) {
if (!$this->entityManager->isOpen()) {
$this->entityManager = $this->doctrine->resetManager();
}
}
答案 13 :(得分:0)
我找到了有关此问题的有趣文章
ArrayList<String> students = new ArrayList<String>();
ArrayList<String> smartStudents = new ArrayList<String>();
ArrayList<String> stupidStudents = new ArrayList<String>();
ArrayList<String> oldStudents = new ArrayList<String>();
ArrayList<String> youngStudents = new ArrayList<String>();
//adding all the students to students list
Collections.addAll(students, "Ram", "Mohan", "Sohan", "Rabi", "Shabbir","Jack", "Johnson", "Peter", "Despina", "Me");
//adding young students to youngStudents list
Collections.addAll(youngStudents, "Ram", "Mohan", "Sohan", "Rabi", "Shabbir");
//adding smart students to oldStudents list
Collections.addAll(oldStudents, "Jack", "Johnson", "Peter", "Despina", "Me");
//adding smart students to smartStudents list
Collections.addAll(smartStudents, "Sohan", "Rabi", "Peter", "Despina");
//adding smart students to stupidStudents list
Collections.addAll(stupidStudents, "Ram", "Mohan", "Shabbir","Jack", "Johnson", "Me");
Scanner input = new Scanner(System.in);
String uInput = "";
System.out.print("This is a students search engine, write 'young' for younger students and 'old' for older ones ");
uInput = input.nextLine();
if(uInput.equals("young")) {
students.removeAll(oldStudents);
} else if (uInput.equals("old")) {
students.removeAll(youngStudents);
}
System.out.print("now write 'Smart' for smarter students and 'Stupid' for less smart students ");
uInput = input.nextLine();
if(uInput.equals("smart")) {
students.removeAll(stupidStudents);
} else if (uInput.equals("Stupid")) {
students.removeAll(smartStudents);
}
System.out.println(students);
答案 14 :(得分:0)
Symfony v4.1.6
Doctrine v2.9.0
在存储库中插入重复项的过程
//begin of repo
/** @var RegistryInterface */
protected $registry;
public function __construct(RegistryInterface $registry)
{
$this->registry = $registry;
parent::__construct($registry, YourEntity::class);
}
//begin of repo
/** @var RegistryInterface */
protected $registry;
public function __construct(RegistryInterface $registry)
{
$this->registry = $registry;
parent::__construct($registry, YourEntity::class);
}
答案 15 :(得分:0)
我有这个问题。这就是我如何解决它。
尝试刷新或持续时,连接似乎已关闭。尝试重新打开它是一个糟糕的选择,因为会产生新的问题。我试着理解连接关闭的原因,发现我在持久化之前做了太多修改。
persist()之前解决了这个问题。
答案 16 :(得分:-1)
使用Symfony 5 / Doctrine 2时,我遇到了相同的错误。我的一个字段是使用MySQL保留字“ order”命名的,这导致DBALException。当您想使用保留字时,必须使用反引号将其名称转义。以注释形式:
$this->registerJs(
"function setButtonValue(stringValue) { alert('Button clicked!'); });",
);
?>
答案 17 :(得分:-1)
The EntityManager is closed.
我遇到了同样的问题。原因是数据库表中缺少列 - 我只需要运行迁移。
答案 18 :(得分:-2)
我遇到了同样的问题。看了几个地方后我就是这样处理的。
//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();
}
希望这有助于某人!
答案 19 :(得分:-2)
// 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();