Una de las problemáticas más grandes a los que se enfrentan los programadores novatos es que sus sistemas tienen “registros a medias”, por ejemplo, imagina que debes registrar un cliente y para hacerlo tu modelo de base de datos requiere hacer múltiples inserciones, es decir, se hará una inserción tras otra en orden de significancia.

El problema de hacer múltiples inserciones en una base de datos radica en que, si una de ellas falla, las subsecuentes también lo harán, generando como consecuencias registros inconclusos en procesos determinados.

Si recuerdas tus clases de Bases de Datos, de seguro alguna vez habrás escuchado hablar de las “transactions”, mismas que por definición son “Interacciones con la base de datos compuestas de varios procesos”, en otras palabras, su función es reflejar el resultado de múltiples consultas a la base de datos siempre y cuando todas se hayan cumplido exitosamente.

Tradicionalmente, para hacer uso de transactions se realizan las consultas a nivel base de datos y posteriormente se llaman las transacciones a través de procedimientos almacenados, sin embargo, Laravel dentro de su facade DB contempla su uso, que en combinación con eloquent nos facilita bastante el trabajo en cuanto a este tema, como se muestra en el ejemplo de a continuación.

Implementación de transacciones en Laravel:

En primer lugar, debemos indicar a nuestra clase el uso de la Facade DB mediante la siguiente sintaxis:

use Illuminate\Support\Facades\DB;

Posteriormente haremos uso de una exception que nos permitirá hacer una manipulación adecuada de las transacciones

try {
} catch (\Exception $e) {
  return $e->getMessage();
}

Al código anterior, debemos anexarle los 3 métodos que nos ofrece Laravel para el uso de transacciones quedando de la siguiente manera:

DB::beginTransaction();
try {
  DB::commit();
} catch (\Exception $e) {
  DB::rollback();
  return $e->getMessage();
}

Explicación:

DB::beginTransaction(); Sirve para inicializar la transacción, aquí le indicamos que el código siguiente contendrá inserciones en base de datos, mismas que no se verán reflejadas a menos que se haga un commit a la misma. Este método se escribe antes del try que contendrá nuestras consultas.

DB::commit(); En caso de que todas las consultas a la BD se realicen con éxito, al leer este método se dará por entendido que todos los cambios realizados anteriormente quedaran reflejados en la base de datos.

DB::rollback(); En caso de que la inserción presente algún error, la excepción pasara al bloque catch donde el método rollback borrara todos los cambios que se hayan hecho después de inicializar la transacción, por lo que con esto evitaremos los “registros a medias” volviendo al estado anterior de la BD antes de iniciar el proceso. Seguido de esto puedes retornar el error o un mensaje personalizado que permita entender cuál fue el fallo en la operación.

Finalmente, las consultas a la BD que desees realizar debes codificarlas después del try { y antes del DB::commit(); como se muestra en el siguiente ejemplo:

DB::beginTransaction();
try {
  $payment = Payment::find($id_payment);
  $payment->id_status = 13;
  $payment->save();
  $card_payment = PaymentCard::find($payment->id_card_payment);
  $card_payment->id_status = 25;
  $card_payment->save();
  DB::commit();
} catch (\Exception $e) {
  DB::rollback();
  return $e->getMessage();
}

Bonus.

Otra manera en que podemos hacer uso de transacciones, es a través de eloquent pero únicamente para consultas individuales anexando el OrFail a los métodos de las mismas por ejemplo:

$payment = Payment::findOrFail($id_payment);
$payment->id_status = 13;
$payment->saveOrFail();

Como puedes notar, el método find() se convierte findOrFail() y el save() pasa a saveOrFail(), este tipo de transacciones vienen implícitas en Eloquent mismas que al ser utilizadas, en caso de que la consulta falle inmediatamente nos retornara una pantalla de error 404, el uso de estas transacciones es bastante útil cuando manejas links para productos, blogs, etc. ya que si se comparte alguna URL cuyos registros ya no existen en la BD no se afectara el flujo de navegación del usuario final.

Código de los ejemplos:

Si gustas, puedes darle un vistazo al código de este ejemplo que se encuentra aquí en mi cuenta personal de Github.

Bueno devs este es el post de la semana,  espero les sea de utilidad en sus proyectos y cualquier duda pueden hacérmela saber en los comentarios, ¡Hasta pronto!

Fuentes de consulta.

https://laravel.com/docs/8.x/database#database-transactions