回滚干 运行 交易后无法继续进一步操作
Cannot Persist Further Operations After Rolling Back a Dry Run Transaction
我有一个 artisan 命令,我正在其中清理一些损坏的数据。在我实际删除数据之前,我想做一个干燥的 运行 并展示删除该数据可能带来的一些影响。
我命令的实质是:
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
...
}
问题是,当我干运行,并确认删除时,实际操作并没有持久化到数据库中。如果我注释掉 dry 运行 并执行命令,该操作会持续存在。我检查了干运行和实际操作前后DB::transactionLevel()
,一切似乎都是正确的。
我也试过使用DB::connection($connection)->pretend(...)
,但还是一样的问题。我也尝试在回滚后做 DB::purge($connection)
和 DB::reconnect($connection)
。
有人知道发生了什么事吗?
(使用 Laravel v6.20.14
)
- 打开MySQL的“常规日志”。
- 运行给你添麻烦的实验。
- 关闭那个日志。
问题可能在日志中很明显;如果不显示日志。
在挖掘源代码后,我发现在模型实例上调用 delete 后,laravel 将 属性 "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 因为它会创建一个浅拷贝
我有一个 artisan 命令,我正在其中清理一些损坏的数据。在我实际删除数据之前,我想做一个干燥的 运行 并展示删除该数据可能带来的一些影响。
我命令的实质是:
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
...
}
问题是,当我干运行,并确认删除时,实际操作并没有持久化到数据库中。如果我注释掉 dry 运行 并执行命令,该操作会持续存在。我检查了干运行和实际操作前后DB::transactionLevel()
,一切似乎都是正确的。
我也试过使用DB::connection($connection)->pretend(...)
,但还是一样的问题。我也尝试在回滚后做 DB::purge($connection)
和 DB::reconnect($connection)
。
有人知道发生了什么事吗?
(使用 Laravel v6.20.14
)
- 打开MySQL的“常规日志”。
- 运行给你添麻烦的实验。
- 关闭那个日志。
问题可能在日志中很明显;如果不显示日志。
在挖掘源代码后,我发现在模型实例上调用 delete 后,laravel 将 属性 "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 因为它会创建一个浅拷贝