我们说我有一个脚本可以将行插入数据库,它看起来像这样:
/* $start is some GET parameter. Any number between 0 and 9900 */
/* Select all objects with ids between $start and $start+99
and put their ids into $ids array */
$qb->select('object');
$qb->from('AppBundle:Object','object');
$qb->where("object.id >= $start");
$qb->andWhere("object.id < $start+100");
$objects = $qb->getQuery()->getResult();
$ids = array();
foreach($objects AS $object) {
$ids[] = $object->getId();
}
/* Create missing objects and insert them into database */
for($id=$start; $id<$start+100; ++$id) {
if(in_array($id, $ids)) continue;
/* Some calculations */
$createdObject = new Object($id, $some, $data);
$em->persist($createdObject);
}
$em->flush();
现在想象一下还没有对象(表格清晰),一个用户以start = 0进入网站。该脚本需要2秒钟才能完成。在完成之前 - 另一个用户以start = 50进入该站点。
我不确定在这种情况下究竟会发生什么,但我认为:
第一个用户输入 - $ ids数组为空,脚本生成ID为0-99的对象。
第二个用户输入 - $ em-&gt; flush表单第一个入口尚未调用,这意味着$ ids数组仍为空(我猜?)。该脚本生成id为50-149
第一个$ em-&gt; flush()调用来自第一个用户入口。它将对象0-99插入数据库。
第二个$ em-&gt; flush()调用来自第二个用户入口。它尝试将对象50-149插入数据库。它失败,因为数据库中已存在id = 50的对象。因此,它实际上并没有在数据库中插入任何内容。
那真的会发生什么?如果是这样 - 如何防止它以及只插入缺少数据库的那些对象的最佳方法是什么?
@edit:这只是一个例子,但在真实的脚本中,id实际上是3列(x,y,z),对象是地图上的一个字段。这个脚本的目的是我希望有一个巨大的地图,一次生成它需要花费太多时间。所以我想只生成一点,然后只有当一些用户试图访问它们时才创建缺少的部分。在某些时候,将创建整个地图,但过程将是错开的。
答案 0 :(得分:1)
这里有2个不良做法:
要回答您的问题 - 如果您为具有预先分配的ID的对象调用$ em-&gt; persist(),并且如果数据库中存在具有相同ID的另一个对象,则不会发生INSERT。相反,现有对象将使用来自较新对象的数据进行更新(之后调用em-&gt; flush()时)。因此,不是2个对象(如预期的那样),数据库中只有1个。所以这就是为什么我真的怀疑你是否需要提前预先分配ID。你应该告诉我更多关于这个的目的:)