En ocasiones, tenemos que ejecutar una o varias consultas a la vez y tenemos que asegurarnos que esas consultas se ejecutan correctamente. Porque, si son varias, puede ser que una dependa de otra. Para asegurarnos que todas las consultas se han ejecutado correctamente y que no ha habido ningún error, en MySQL existen las transacciones. Lo que hacen las transacciones es asegurarte que si las consultas se han ejecutado sin ningún error, se hagan los cambios en base de datos y, si ha habido algún error, volver al estado inicial antes de haber hecho las consultas, es decir, no guarda nada en la base de datos para que no haya datos sueltos.
La clase DB de Laravel nos provee unos métodos que nos permiten hacer esto de manera muy fácil. Vamos a ver un ejemplo, utilizando un trozo del código del post anterior, al cual le vamos a añadir este código:
1 2 3 4 5 6 |
DB::transaction(function () use ($post, $comment) { $post->comments()->save($comment); $post->last_comment_at = now(); $post->save(); }); |
Le estamos indicando que guarde el comentario relacionado al post y que nos añada la fecha del último comentario al post, lo que pasa es que ese campo (last_comment_at) no existe en la tabla de posts. Al no existir, lanza una excepción y al estar dentro del método transaction no se inserta nada en la base de datos. También, podríamos lanzar una excepción propia dentro del método transaction para después tratarla y hacer lo que queramos. Tendríamos que crearla en app/Exceptions y ejecutarla así:
1 |
throw new MyCustomException(‘Mensaje de error que queramos’); |
Como hemos visto, el método transaction lo hace automático, pero también podríamos hacer ejecutar una transacción manualmente y tener más control sobre donde hacer el commit (guardar en base de datos) y rollback (vuelta al estado inicial, sin guardar nada):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
DB::beginTransaction(); try { $post->comments()->save($comment); $post->last_comment_at = now(); $post->save(); DB::commit(); } catch (\Exception $e) { DB::rollback(); throw $e; } catch (\Throwable $e) { DB::rollback(); throw $e; |
En el bloque try, ponemos el código que queremos que se ejecute sin errores (las consultas) y si hubiese algún error el catch captaría la excepción. En este caso, como ya he comentado en el ejemplo anterior, hay un error. Por tanto, de los datos que estamos intentando insertar en la base de datos, no se inserta nada.
-