Livelli di servizio multipli e transazioni di database
-
06-07-2019 - |
Domanda
Mi sto solo chiedendo come gestire al meglio le transazioni su più livelli di servizio. I livelli di servizio utilizzano un ORM per archiviare e recuperare dal database. Le transazioni devono essere conosciute e gestite all'interno dei singoli livelli di servizio? O dovrebbero essere gestiti da un altro livello?
Ad esempio: ho due livelli di servizio per utenti e client. Vorrei:
1) Crea e salva un nuovo client
2) Crea e salva un nuovo utente
3) Assegnare tale utente al client
Tutto in un'unica transazione.
Un semplice esempio potrebbe apparire così:
$userManagementService = new UserManagementService;
$newUserData = array(...);
$newUser = $userManagementService->create($newUserData);
$clientManagementService = new ClientManagementService;
$newClientData = array(...);
$newClient = $clientManagementService->create($newClientData);
$userManagementService->assignUserToClient($newUser, $newClient);
Dove dovrebbe andare la logica delle transazioni?
Soluzione
Non tentare di eseguire transazioni nidificate all'interno dei livelli di servizio o all'interno dell'ORM.
Le transazioni sono globali alla connessione DB. A meno che RDBMS non supporti le transazioni nidificate in modo nativo e l'API DB espone transazioni nidificate, è possibile riscontrare anomalie.
Per i dettagli, vedere la mia risposta a Come rilevare che la transazione è già stata avviata?
Dato che stai usando PHP, l'ambito delle tue transazioni è al massimo una singola richiesta. Quindi dovresti usare solo le transazioni gestite dal contenitore, non il livello di servizio transa. Cioè, avvia la transazione all'inizio della gestione della richiesta e esegui il commit (o il rollback) al termine della gestione della richiesta.
Se si verifica un'eccezione che richiede un rollback all'interno delle azioni ORM nidificate, creane una bolla usando un'eccezione e lascia che il contenitore (ovvero il tuo controller di azioni PHP) si occupi di essa.
Altri suggerimenti
Stai affrontando un'aggregazione di transazioni? Questo pseudo codice corrisponde a quello che penso tu stia dicendo?
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
In qualsiasi momento il rollback di una transazione nidificata genererà probabilmente un'eccezione e tali eccezioni porterebbero logicamente al rollback di tutte le transazioni nidificate in commit in due fasi .
Potrei non avere quello che cerchi dopo.