Doctrine2 - 一次性多次插入

时间:2013-09-06 09:33:35

标签: php mysql symfony doctrine-orm

我是Doctrine的新手,对我来说还有一些模糊的区域。在这种情况下,我使用循环和实体管理器在数据库中插入新记录。它工作正常,但我注意到Doctrine按实体进行一次插入查询,这可能变得非常庞大。

使用Doctrine2和Symfony 2.3,我想知道如何设置它,这样它只会产生1个插入查询及其中的所有值(我们当然只讨论1个实体)。

我的意思是改变这个:

INSERT INTO dummy_table VALUES (x1, y1)    
INSERT INTO dummy_table VALUES (x2, y2)

INSERT INTO dummy_table VALUES (x1, y1), (x2, y2)

这是我的代码:

$em = $this->container->get('doctrine')->getManager();

foreach($items as $item){
    $newItem = new Product($item['datas']);
    $em->persist($newItem);
}

$em->flush();

3 个答案:

答案 0 :(得分:41)

根据this answer,Doctrine2不允许您将多个INSERT语句合并为一个:

  

有些人似乎在想为什么Doctrine不使用   多插入(插入(...)值(...),(...),(...),...

     

首先,只有mysql和更新版本支持此语法   postgresql版本。其次,没有简单的方法来掌握所有   使用时在这样的多插入中生成的标识符   AUTO_INCREMENT或SERIAL和ORM需要标识符以进行标识   管理对象。最后,插入性能很少   ORM的瓶颈。普通插入物的速度足够快   大多数情况下,如果你真的想做快速批量插入,那么a   多插入不是最好的方式,即Postgres COPY或Mysql   LOAD DATA INFILE快几个数量级。

     

这就是为什么不值得努力实施的原因   抽象,在mysql和postgresql上执行多插入   ORM。

您可以在此处阅读有关Doctrine2批处理的更多信息: http://www.doctrine-project.org/blog/doctrine2-batch-processing.html

您可以切换到DBAL或通过在设定数量的插入后刷新实体管理器来小批量处理数据:

$batchSize = 20;

foreach ($items as $i => $item) {
     $product = new Product($item['datas']);

     $em->persist($product);

     // flush everything to the database every 20 inserts
     if (($i % $batchSize) == 0) {
         $em->flush();
         $em->clear();
    }
}

// flush the remaining objects
$em->flush();
$em->clear();

答案 1 :(得分:0)

您可以使用executeUpdate($query, array $params = array(), array $types = array())接口的DriverConnection方法来执行此操作。但是绑定多个参数有点棘手。

数据:

$postMetaData = [
    [
        'post_id' => $product->getId(),
        'meta_key' => '_visibility',
        'meta_value' => 'visible',
    ],
    [
        'post_id' => $product->getId(),
        'meta_key' => '_stock_status',
        'meta_value' => $insert['in_stock'] ? 'instock' : 'outofstock',
    ]
];

批量更新方法:

public function updateOrCreateBulk($posts, \Doctrine\DBAL\Connection $connection)
{

    $placeholders = [];
    $values = [];
    $types = [];

    foreach ($posts as $columnName => $value) {
        $placeholders[] = '(?)';
        $values[] = array_values($value);
        $types[] = \Doctrine\DBAL\Connection::PARAM_INT_ARRAY;
    }

    return $connection->executeUpdate(
        'INSERT INTO `wp_postmeta` (`post_id`, `meta_key`, `meta_value`)  VALUES ' . implode(', ', $placeholders) . ' ON DUPLICATE KEY UPDATE `meta_value` = VALUES(`meta_value`)',
        $values,
        $types
    );
}

答案 2 :(得分:-6)

我还没有对它进行过测试,但似乎可以通过集合进行测试。

$collection = new Doctrine_Collection('tablename');
$collection->add($record1);
$collection->add($record2);
$collection->add($record3);
$collection->add($record4);
$collection->save();

当然你应该在循环中添加。