持久化实体而不将其附加到 EntityManager
Posted
技术标签:
【中文标题】持久化实体而不将其附加到 EntityManager【英文标题】:Persist an entity without attaching it to the EntityManager 【发布时间】:2016-04-09 10:07:18 【问题描述】:我想从 XML 文件中批量导入 Doctrine 实体。
XML 文件可能非常大(最多 100 万个实体),因此我无法以传统方式持久化所有实体:
$em->beginTransaction();
while ($entity = $xmlReader->readNextEntity())
$em->persist($entity);
$em->flush();
$em->commit();
我很快就会超过我的内存限制,而 Doctrine 并不是真正设计用于处理那么多托管实体。
我不需要跟踪对持久化实体的更改,只是为了持久化它们;因此我不希望它们由 EntityManager 管理。
是否可以在不由 EntityManager 管理的情况下保留实体?
我想到的第一个选项是在持久化后立即将其分离:
$em->beginTransaction();
while ($entity = $xmlReader->readNextEntity())
$em->persist($entity);
$em->flush($entity);
$em->detach($entity);
$em->commit();
但这在 Doctrine 中相当昂贵,并且会减慢导入速度。
另一种选择是使用Connection
对象和准备好的语句直接将数据插入数据库,但我喜欢实体的抽象,理想情况下希望存储对象直接。
【问题讨论】:
【参考方案1】:您可以在每次插入后调用clear
(将所有实体与管理器分离)和flush
,而不是在每次插入后使用detach
和flush
,这应该会明显更快:
Doctrine 中的批量插入最好分批执行,取 事务性后写行为的优势 实体管理器。以下代码显示了插入 10000 的示例 批量大小为 20 的对象。您可能需要尝试使用 批量大小以找到最适合您的大小。大批量 大小意味着更多的准备好的语句在内部重用,但也意味着更多 在冲洗期间工作。
https://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/batch-processing.html
如果可能,我建议避免批量操作的事务,因为它们往往会减慢速度:
//$em->beginTransaction();
$i = 0;
while ($entity = $xmlReader->readNextEntity())
$em->persist($entity);
if(++$i % 20 == 0)
$em->flush();
$em->clear(); // detaches all entities
$em->flush(); //Persist objects that did not make up an entire batch
$em->clear();
//$em->commit();
【讨论】:
我希望让 EntityManager 保持当前状态,但这毕竟不是什么大问题。我还看到clear()
接受一个可选的类名来仅分离给定类的实体,这在这种情况下会很有帮助。所以我想这是目前唯一的方法!以上是关于持久化实体而不将其附加到 EntityManager的主要内容,如果未能解决你的问题,请参考以下文章