我有这个简单的功能,我想进行laravel交易。它正在插入第一个(SecondaryShare),而第二个(Primary Share)包含错误,一旦发生错误,我想回滚并删除SecondaryShare。
try {
DB::transaction(function () use ($request) {
$Share = new SecondaryShares();
$Share->secondary_name = $request->secondaryName;
$Share->primary_id = $request->primaryId
$Share->save();
//error in primaryname==> correct is primary_name
$Share = new PrimaryShares();
$Share->primaryname = $request->primaryName;
$Share->percentage = $request->percentage;
$Share->visibility = $visibility;
$Share->save();
});
} catch (\Exception $e) {
dd('failed');
}
dd('worked');
我该如何解决?
谢谢。
答案 0 :(得分:3)
您使用交易系统的方式错误。有两种方法可以使用它,并且您将它们混在一起,尽管绝对不要这样做。
您可以将代码放入事务关闭中。一旦引发Exception
(实际上是Throwable
)或从这些类型继承的任何异常类型,交易将被回滚,并且异常将被重新抛出关闭处理程序:
DB::transaction(function () {
$model1 = MyModel::create();
// model2 will not be created if model1 couldn't be created
$model2 = MyModel::create();
});
您还可以使用try-catch包裹事务关闭以捕获任何事务异常:
try {
DB::transaction(function () {
$model1 = MyModel::create();
// model2 will not be created if model1 couldn't be created
$model2 = MyModel::create();
});
} catch (\Exception $e) {
Log::error('Insert failed', ['exception' => $e]);
return redirect()->back()->withInput();
}
return redirect()->route('form.success');
或者,您也可以自己控制事务逻辑。但是要小心,这种方式更危险,因为它很容易发生,忘记了回滚或提交:
DB::beginTransaction();
$model1 = MyModel::create();
if ($model1->exists !== true) {
DB::rollBack();
Log::error('Insert 1 failed');
return redirect()->back()->withInput();
}
$model2 = MyModel::create();
if ($model2->exists !== true) {
DB::rollBack();
Log::error('Insert 2 failed');
return redirect()->back()->withInput();
}
DB::commit();
return redirect()->route('form.success');
我认为,使用选项2会产生更多的代码,并且可读性较低。
顺便说一句,Laravel使用自定义数据库异常。它将抛出\Illuminate\Database\QueryException
而不会抛出\PDOException
。
答案 1 :(得分:0)
我的数据库是InnoDB,但我发现这些表是MyISAM。 通过向迁移添加以下代码来解决: $ table-> engine =“ InnoDB”;