无法在撤销演示事务后持续执行进一步操作

4

我有一个艺匠命令,用于清理一些已经出错的数据。在实际删除数据之前,我想要先进行模拟运行,并展示删除这些数据可能带来的影响。

我的命令的核心是:

    public function handle()
    {
        ...

        $this->dryRun($modelsToDelete); // Prints info to user

        if ($this->confirm('Are you sure you want to delete?') {
            $modelsToDelete->each->forceDelete();
        }
        ...
    }

    public function dryRun($modelsToDelete)
    {
        ...

        DB::connection($connection)->beginTransaction();
        $before = $this->findAllOrphans($models);

        $modelsToDelete->each(function ($record) use ($bar) {
            $record->forceDelete();
        });

        $after = $this->findAllOrphans($models);
        DB::connection($connection)->rollBack();

        // Print info about diff
        ...
    }

问题在于,当我进行试运行并确认删除时,实际操作没有在数据库中持久化。如果我注释掉试运行并执行该命令,则操作会持久化。我已经检查了试运行和实际操作之前和之后的 DB::transactionLevel(),一切似乎都正确。
我还尝试使用 DB::connection($connection)->pretend(...),但问题仍然存在。我也尝试在回滚后执行 DB::purge($connection)DB::reconnect($connection)
有人有什么想法吗?
(使用Laravel v6.20.14

你的 DB::connection($connection)->transaction(function() {}) 有什么进展了吗? - Chinh Nguyen
这里也不行,@ChinhNguyen - Kurt Friars
你确定你的代码通过了 dryRun 检查吗? - Chinh Nguyen
我不确定你的意思,@ChinhNguyen。我知道干运行会执行并显示差异。但是如果我选择实际删除,它将不会真正被删除。如果我不使用干运行命令,它将会真正被删除。 - Kurt Friars
我还不知道原因,但我找到了解决您问题的方法。当调用dryRun时,请传递$modelsToDelete对象的深拷贝,例如:$this->dryRun(unserialize(serialize($modelsToDelete)));。我猜测这是因为在调用forceDelete()后,模型将不会再次查询删除(只是猜测)。 - Chinh Nguyen
谢谢@ChinhNguyen!我会调查一下,如果行的话,请创建一个答案,我会授予悬赏。 - Kurt Friars
2个回答

2
在查看源代码后,我发现 Laravel 在你调用模型实例的 delete 方法后会将属性 "exists" 设置为 false,并且不会再执行删除查询。你可以参考以下内容:

https://github.com/laravel/framework/blob/9edd46fc6dcd550e4fd5d081bea37b0a43162165/src/Illuminate/Database/Eloquent/Model.php#L1173 https://github.com/laravel/framework/blob/9edd46fc6dcd550e4fd5d081bea37b0a43162165/src/Illuminate/Database/Eloquent/Model.php#L1129

为了使模型实例在 dryRun 后可以被删除,您应该将深度复制传递给 dryRun,例如:
$this->dryRun(unserialize(serialize($modelsToDelete)));

注意:不要使用php clone,因为它创建的是浅拷贝。

0
  1. 打开MySQL的“通用日志”。
  2. 运行出现问题的实验。
  3. 关闭该日志。

问题可能会在日志中变得明显;如果不是,请向我们展示日志。


我现在的注意力有点分散,我很快会上传一些日志。感谢你的建议。 - Kurt Friars

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接