【问题标题】:Persist an entity without attaching it to the EntityManager持久化实体而不将其附加到 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 对象和准备好的语句直接将数据插入数据库,但我喜欢实体的抽象,理想情况下希望存储对象直接。

【问题讨论】:

    标签: doctrine-orm


    【解决方案1】:

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

    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() 接受一个可选的类名来仅分离给定类的实体,这在这种情况下会很有帮助。所以我想这是目前唯一的方法!
    猜你喜欢
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 1970-01-01
    • 2015-04-08
    • 2015-11-15
    相关资源
    最近更新 更多