一次保存多个实体时如何允许失败?

How to allow failures when saving multiple entities at once?

因此,我可能有数百行需要插入到数据库中。没有验证数据的唯一性。

但是,在数据库中,3 列之间有一个约束条件,即合并后必须是唯一的。有时,这种唯一性失效,导致整个保存操作失败。

有没有办法忽略 Table::saveMany() 调用中的失败并继续保存所有其他记录?也许稍后记录错误,但仍继续保存其余记录,而不是完全使整个操作失败?

不,没有,请查看 API 的描述和 Table::saveMany() 的源代码,它只是将所有实体保存在一个循环中,该循环将停止并回滚事务,以防万一 Table::save()失败。

The records will be saved in a transaction which will be rolled back if any one of the records fails to save due to failed validation or database error.

https://api.cakephp.org/3.6/class-Cake.ORM.Table.html#_saveMany

如果你想允许失败,那你就得自己处理,保存每条记录,捕获可能的异常,并检查保存操作结果。这是一个简单粗暴的示例,其中 $table 是要保存的 table,$entities 是一个实体数组:

$result = $table->getConnection()->transactional(
    function () use ($entities, $table) {
        foreach ($entities as $entity) {
            try {
                $result = $table->save($entity, ['atomic' => false]);
            } catch (\PDOException $exception) {
                $result = $exception;
            }

            if ($result !== true) {
                // log an error...
            }
        }

        return true;
    }
);

另见

您可以采取几种方法来解决这个问题。

  1. 而不是使用 Table::saveMany() 做一个循环,只使用 Table::save() 并记录失败的内容,以便您稍后进行调查。

  2. 将您的大工作拆分成较小的批次。如果您必须说 1,000 条记录,请将其分成 100 条记录批次,并对每批次使用 Table:saveMany()。这样,当某些事情失败时,只有当前批次失败,而不是整个保存过程。

  3. 有点危险(并且 NOT 推荐)是覆盖 Table::save() 方法,即使它无法存储记录也不会失败。