保持实体而不将其附加到EntityManager

时间:2016-04-09 10:07:18

标签: doctrine-orm

我想从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 个答案:

答案 0 :(得分:2)

不是在每次插入后使用detachflush,而是可以批量调用clear(将所有实体与管理器分离)和flush显着更快:

  

Doctrine中的批量插入最好分批进行   一个事务性的后写行为的优点   EntityManager的。以下代码显示了插入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();