Reputation: 1
I have this simple function and I want to make laravel transaction. It is inserting the first(SecondaryShare) while the second(Primary Share) contains error and I want to rollback and delete the SecondaryShare once the error occured.
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');
How can I fix it?
Thanks in advance.
Upvotes: 0
Views: 1245
Reputation: 1
My database is InnoDB but i figured out that the tables is MyISAM. solved by adding this line of code to migration: $table->engine = "InnoDB";
Upvotes: 0
Reputation: 6544
You are using the transaction system the wrong way. There is two ways to use it and you are mixing them up, although that should never be done.
You can put your code into a transaction closure. As soon as an Exception
(actually Throwable
) or any exception type inheriting from these types is thrown, the transaction will be rolled back and the exception will be re-thrown by the closure handler:
DB::transaction(function () {
$model1 = MyModel::create();
// model2 will not be created if model1 couldn't be created
$model2 = MyModel::create();
});
You can also wrap the transaction closure with a try-catch to catch any transaction exception:
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');
Or alternatively, you can control the transaction logic yourself. But be careful, this way is more dangerous because it happens quite easily that one forgets a rollback or commit:
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');
In my opinion, using option 2 yields a lot more code and is less readable.
By the way, Laravel is using custom database exceptions. It will throw a \Illuminate\Database\QueryException
and no \PDOException
.
Upvotes: 3