Volver a la página principal
sábado 28 septiembre 2024
53

Cómo usar DB::transaction() en Laravel para manejar transacciones de base de datos

Definición de DB::transaction() en Laravel

El método DB::transaction() acepta un closure (función anónima) que encapsula las operaciones a ejecutar dentro de la transacción. Si el closure se ejecuta sin errores, la transacción se confirma (commit). Si ocurre una excepción o error, la transacción se revierte (rollback).

Ejemplo básico de uso:

use Illuminate\Support\Facades\DB;

DB::transaction(function () {
    DB::table('users')->update(['active' => false]);
    DB::table('orders')->delete();
});

En este ejemplo, ambas operaciones (update y delete) se ejecutan como parte de una transacción. Si alguna falla, ninguno de los cambios se aplicará en la base de datos.

Algunos ejemplos de uso de DB::transaction()

1. Transacción con múltiples consultas:

Supongamos que necesitas actualizar el saldo de un usuario y registrar la transacción en otra tabla. Si alguna de las operaciones falla, no se aplican los cambios:

DB::transaction(function () use ($userId, $amount) {
       DB::table('users')
           ->where('id', $userId)
           ->decrement('balance', $amount);

       DB::table('transactions')->insert([
           'user_id' => $userId,
           'amount' => $amount,
           'type' => 'withdrawal',
           'created_at' => now(),
           'updated_at' => now()
       ]);
   });

Si, por ejemplo, la inserción en la tabla transactions falla, el saldo del usuario no se verá afectado.

2. Manejo de excepciones manualmente dentro de la transacción:

Si necesitas capturar errores específicos dentro de la transacción, puedes usar un bloque try-catch:

try {
       DB::transaction(function () use ($orderData) {
           DB::table('orders')->insert($orderData);

           DB::table('inventory')
               ->where('product_id', $orderData['product_id'])
               ->decrement('stock', $orderData['quantity']);
       });
   } catch (\Exception $e) {
       // Manejo de error
       return back()->with('error', 'Hubo un problema con la transacción.');
   }

Si alguna consulta falla, DB::transaction() lanza una excepción, permitiéndote gestionar el error como consideres.

3. Anidar transacciones (DB::beginTransaction y DB::commit):

Laravel también permite el uso de DB::beginTransaction(), DB::commit() y DB::rollback() manualmente:

DB::beginTransaction();
   
   try {
       DB::table('users')->update(['active' => false]);
       DB::table('orders')->delete();
       
       DB::commit(); // Confirmar la transacción
   } catch (\Exception $e) {
       DB::rollback(); // Revertir si hay un error
       throw $e; // Lanzar la excepción nuevamente para gestionarla
   }

Esto permite un control más granular en situaciones complejas donde se deben gestionar transacciones en varias capas del código.

4. Retornar valores desde una transacción:

Puedes devolver resultados dentro de un DB::transaction():

$result = DB::transaction(function () {
       $user = DB::table('users')->where('email', 'john@example.com')->first();
       DB::table('log')->insert(['user_id' => $user->id, 'action' => 'login']);

       return $user;
   });

   echo $result->name;

Aquí, el valor retornado desde el closure ($user) se asigna a $result solo si la transacción se completa con éxito.

5. Forzar un rollback manualmente:

Si necesitas revertir una transacción sin que ocurra una excepción, puedes usar DB::rollBack() dentro del closure:

DB::transaction(function () {
       DB::table('users')->update(['active' => false]);

       // Condición personalizada para revertir
       if (DB::table('orders')->count() < 1) {
           DB::rollBack();
       }
   });

Esto revertirá la transacción sin necesidad de lanzar una excepción.

Referencia oficial

Para más información sobre el uso de transacciones en Laravel, consulta la documentación oficial de Laravel.

Etiquetas:
laravel php
Compartir:
Creado por:
Author photo

Jorge García

Fullstack developer