August 20, 2021

What is a database transaction?

The problem

It’s common for me to have to run a series of queries on my applications’ database. Typically, I’m also looking to make sure that if any of those create/update/delete operations fail, the application can roll back any changes that were made. Manually doing this at the application layer can be challenging, tedious, and borderline impossible depending on your system’s setup. But thankfully, Laravel has a fantastic way to solve exactly that problem.

The solution

Laravel’s DB facade contains a lot of really useful abstractions for your database management system of choice. The one I want to focus in on is the transaction method. A great usage example of the transaction method can be found in the DeleteUser action that comes along with Laravel Jetstream:

public function delete($user)
{
    DB::transaction(function () use ($user) {
        $this->deleteTeams($user);
        $user->deleteProfilePhoto();
        $user->tokens->each->delete();
        $user->delete();
    });
}

So what does the transaction method DO, exactly?

Let’s start with the closure function. For the most part, the code in here runs exactly like it would anywhere else in your Laravel application, except for one special feature you get because of the transaction method: rollbacks.

Like I mentioned earlier, these are a series of database queries that I would want to make sure were only finalized if all of them passed. If that wasn’t the case, we could end up in a state where, for a given User, we could have deleted their Teams, but failed to delete their profile photo, tokens, and the User themselves. Not an idea scenario, to say the least.

But, since this series of database queries has been wrapped into the transaction method, if any one of them fails, all of the queries up until that point are rolled back, and none of the queries in the transaction are committed to the database. So in the previous scenario, were the deletion of the User's profile photo to fail, their teams would no longer be deleted, and we’d be right back in the same spot we were prior to attempting the delete method.

I love the simplicity of this example from Jetstream, but where would you or where do you use transactions in your applications? Drop me a line and let me know!