php - MĂșltiples capas de servicio y transacciones de base de datos
database design-patterns (2)
Me pregunto cómo manejar mejor las transacciones en varias capas de servicio. Las capas de servicio usan un ORM para almacenar y recuperar desde la base de datos. ¿Deben conocerse y manejarse las transacciones dentro de las capas de servicio individuales? ¿O deberían ser manejados por otra capa?
Por ejemplo: tengo dos capas de servicio para usuarios y clientes. Me gustaría:
1) Crear y guardar un nuevo cliente
2) Crear y guardar un nuevo usuario
3) Asignar ese usuario al cliente
Todo dentro de una sola transacción.
Un ejemplo simple podría verse así:
$userManagementService = new UserManagementService;
$newUserData = array(...);
$newUser = $userManagementService->create($newUserData);
$clientManagementService = new ClientManagementService;
$newClientData = array(...);
$newClient = $clientManagementService->create($newClientData);
$userManagementService->assignUserToClient($newUser, $newClient);
¿A dónde debe ir la lógica de las transacciones?
¿Estás frente a una agregación de transacciones? ¿Este pseudo código coincide con lo que creo que estás diciendo?
try
begin application transaction
begin ORM transaction 1
create new user
commit request
begin ORM transaction 2
create new client
commit request
begin ORM transaction 3
create user client association
commit request
commit application tx
catch()
abort ORM tx 3
abort ORM tx 2
abort ORM tx 1
abort app tx
En cualquier punto, una reversión de una transacción anidada arrojará una excepción, y esas excepciones lógicamente revertirán todas las transacciones anidadas en la confirmación en dos fases .
Puede que no obtenga lo que buscas, aunque.
No intente hacer transacciones anidadas dentro de las capas de servicio o dentro del ORM.
Las transacciones son globales a la conexión DB. A menos que su RDBMS admita transacciones anidadas de forma nativa y su API DB expone transacciones anidadas, puede encontrar anomalías.
Para obtener más información, consulte mi respuesta a ¿Cómo detectar esa transacción que ya se inició?
Como usa PHP, el alcance de sus transacciones es como máximo una sola solicitud. Por lo tanto, solo debe usar transacciones administradas por contenedor, no transacciones de capa de servicio. Es decir, comience la transacción al inicio de la gestión de la solicitud y comprométala (o retrotúyala) cuando termine de gestionar la solicitud.
Si se produce una excepción que requiere una reversión en lo profundo de las acciones ORM anidadas, entonces aumente la burbuja utilizando una excepción y deje que el contenedor (es decir, su controlador de acción PHP) se encargue de ello.