Database Transactions in Laravel with saveOrFail, updateOrFail, and deleteOrFail
Arie Visser • October 26, 2021
laravel php databaseWhen you want to rollback a set of database operations if one of them fails, you can execute them within a database transaction.
Laravel provides several techniques to do this.
One of them, that I hadn't seen before, is by using the saveOrFail
, updateOrFail
, and deleteOrFail
methods.
First, I would like to show briefly what a transaction is.
The transaction
method in Laravel
Imagine, you have a user model, that you want to inactivate, and unsubscribe at the same time.
When the queriy is executing, something may fail, and you can end up with inconsistent results in your database.
To prevent this, you can rollback the query automatically if an exception is thrown by using Laravel's transaction
method like this:
use Illuminate\Support\Facades\DB;
use App\Models\User;
DB::transaction(function () {
User::where('id', 1)->update(['active' => false, 'subscribed' => false]);
});
You can add as many statements as you like to the transaction
method.
They will all be rolled back when one of them fails, before the exception is thrown.
The saveOrFail
, updateOrFail
, and deleteOrFail
methods.
When you only are adding a single statement to a transaction, Laravel provides three shorthand methods that are available on the model, saveOrFail
, updateOrFail
, and deleteOrFail
.
These methods are not to be confused with the
findOrFail
andfirstOrFail
methods. ThefindOrFail
andfirstOrFail
methods are not wrapped in a transaction, but will return a 404 when no model is found.
These methods will wrap the statement in a transaction. Let's look at the definition of saveOrFail
:
public function saveOrFail(array $options = [])
{
return $this->getConnection()->transaction(function () use ($options) {
return $this->save($options);
});
}
The save
method, is added to a transaction when executed by saveOrFail
.
Database statements that are executed by updateOrFail
and deleteOrFail
will also be added to a transaction.
As a result, the update
and delete
statementa from the previous example, could be rewritten like this:
use App\Models\User;
User::where('id', 1)->first()->updateOrFail(['active' => false, 'subscribed' => false]);
This can make your code just a bit cleaner. When there is an exception, all database operations will be rolled back first.
When you need more control, it is also possible to begin, rollback and commit transactions manually.
A more in depth discussion of transactions can be found in the Database Transactions in Laravel article, written by Chris Fidao.