【发布时间】:2022-12-16 09:13:35
【问题描述】:
我正在从事一个基于 Symfony + Doctrine 的项目。当长时间运行的导入操作(解析数据、创建实体、持久化实体等)期间发生异常时,实体管理器关闭.
我还尝试重新打开实体管理器,但我无法正确使用它,并且在尝试保留其他实体时得到 EntityNotFoundException 或 ORMInvalidArgumentException。
那么:如何正确地重新打开一个关闭的实体管理器以便能够再次使用它?
细节:
- 为避免其他用户操作与正在运行的导入发生冲突,用户帐户在导入开始前被锁定。
- 这是通过从数据库查询当前用户的
ImportLock实体来完成的。如果不存在这样的锁,则会创建一个新实体。锁定设置为活动并持久。如果活动锁已经存在,则另一个导入处于活动状态并且不会启动当前导入。 -
transaction开始处理导入 - 解析导入数据,创建并保存实体
- 如果一切正常,则提交事务并将锁设置为非活动状态。完毕。
- 但是,当导入已经存在的数据时,会抛出
UniqueConstraintViolationException关闭实体管理器. - 虽然捕获到异常并重置实体,但无法更新锁定实体。
代码:
$lockRepo = $this->entityManager->getRepository(ImportLock::class);
$lock = $lockRepo->findOneByUser($user);
if (!$lock) {
$lock = new ImportLock();
}
if ($lock->isActive()) {
// Import already running --> cancel
return;
}
$lock->setActive();
$this->entityManager->persist($lock);
$this->entityManager->flush();
// Import
try {
$this->entityManager->getConnection()->beginTransaction();
doImport();
$this->entityManager->getConnection()->commit();
} catch (\Exception $e) {
$this->entityManager->getConnection()->rollback();
if (!$this->entityManager->isOpen()) {
// Step 1
$this->doctrineRegistry->resetManager();
// Step 2
$lockRepo = $this->entityManager->getRepository(ImportLock::class);
$lock = $lockRepo->findOneById($lock->getId()); // look up entity using Id to avoid using the $user which was handled by the "old" entity manager
}
} finally {
$lock->setInactive();
$this->entityManager->persist($lock); // <-- Exception
$this->entityManager->flush();
}
根据我的尝试,我在尝试保留锁时会遇到不同的异常:
-
Doctrine\ORM\Exception\EntityManagerClosed当实体管理器未重新打开/重置时(未执行第 1 步和第 2 步) -
Doctrine\\ORM\\EntityNotFoundException(code: 0): Unable to find "My\\Entity\\User\" entity identifier associated with the UnitOfWork重置实体管理器后未重新加载$lock(未执行第 2 步) -
Doctrine\\ORM\\ORMInvalidArgumentException(code: 0): A new entity was found through the relationship 'My\\Entity\\ImportLock#user' that was not configured to cascade persist operations for entity: My\\Entity\\User@621重置实体管理器并重新加载$lock(执行第 1 步和第 2 步)。
似乎以某种方式使用“旧”实体管理器查询/创建的$lock 无法与“新”(重新打开)实体管理器一起正确使用。
如何解决这个问题?
【问题讨论】:
-
您是否尝试过显式设置事务并且在出现异常的情况下,除了回滚之外您还解锁记录!?
标签: symfony doctrine entitymanager