Symfony3 Doctrine:不会因错误而停止的交易

时间:2018-01-27 06:52:23

标签: symfony transactions doctrine

默认情况下,当出现错误时,事务会回滚所有内容。我希望它能在没有任何回滚的情况下记录错误。有可能吗?

目前我在foreach循环中正在冲洗,当然在数据库中插入数千行是很长的。但是我真的需要记录一切:要么成功要么有关当前正在处理的行的详细信息,如果错误是由php因数据验证失败或者是数据库错误,如UniqueConstraintViolationException(因为脚本可能会多次运行)。

有没有办法在交易中执行此操作?或者还有其他方法吗?

这是我到目前为止所拥有的。它完全符合我的要求,但正如预期的那样,这是一个非常漫长而昂贵的操作:

    // $data is the content of the file
    foreach ($data as $key => $project) {
        // Validate data in the CSV file
        $project = $this->validateData($project);

        $newProject
            ->setStatus($project['Status'])
            ->setSiteName($project['SiteName'])
            // .....
            ;

        // Update if necessary
        $this->getManager()->merge($newProject);

        // Catch errors during DB save
        try {
            $this->getManager()->flush();
            $data[$key]['ImportStatus'] = 'imported';
        } catch (\Exception $e) {
            if ($e instanceof UniqueConstraintViolationException) {
                $data[$key]['ImportStatus'] = 'already imported';
            } else {
                $message = $e->getMessage();

                $errors[] = $message;
                $data[$key]['ImportStatus'] = 'rejected';
                $data[$key]['RejectionCause'] = str_replace(array("\r", "\n"), '', $message);
            }

            // After every error the Manager is closed, reset it....
            $this->getContainer()->get('doctrine')->resetManager();

            // ... so we can open it again
            $this->setManager($this->getContainer()->get('doctrine')->getManager());
        }
    }

3 个答案:

答案 0 :(得分:0)

整个事务的想法是运行整个SQL代码或不运行(回滚)

AFAIK不可能只记录交易中的错误。

你应该关注错误出现的原因,而不是绕过它。

答案 1 :(得分:0)

即使在某些语句失败后也想尝试所有插入语句(例如,根据结果修改后你会尝试失败的语句)?在那种情况下,我不认为交易的使用是充分的,因为其性质,正如Michal之前解释的那样。您可以创建一个循环来插入并持久化并输出每个插入中捕获的所有错误的日志。

$cnt = 0;
foreach ($data as $line){
    try{
        // create $entity from $line
        $em->persist($entity);
        $cnt++;
    }catch (Exception $e) {
        throw $e;
        // output log with the content of the inserted data, for the later use
    }
    if ($cnt%100 == 0){
        $em->flush();
        $em->clear();
    }
}
$em->flush();
$em->clear();

在这个例子中,我为每100个语句放置了flush语句,因为每行的刷新成本太高,但有时可能会导致另一个性能问题或内存泄漏(我认为你应该试一试)。

bulk insert

答案 2 :(得分:0)

您可以使用多个连接到同一个数据库,嵌套事务(http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/transactions.html)或try / catch来捕获回滚异常,然后将有关错误的信息插入到DB中。

相关问题