Multiple Service Layers and Database Transactions

database, design-patterns, domain-driven-design, php, transactions

Solution

Do not try to do nested transactions within service layers or within the ORM.

Transactions are global to the DB connection. Unless your RDBMS supports nested transactions natively and your DB API exposes nested transactions, you can run into anomalies.

For details, see my answer to How do detect that transaction has already been started?

Since you're using PHP, the scope of your transactions is at most a single request. So you should just use container-managed transactions, not service-layer transa. That is, start the transaction at the start of handling the request, and commit (or rollback) as you finish handling the request.

If an exception requiring a rollback occurs deep within nested ORM actions, then bubble that up by using an Exception, and let the container (i.e. your PHP action controller) take care of it.

Problem

I'm just wondering how to best handle transactions across multiple service layers. The service layers use an ORM to store and retrieve from the database. Should the transactions be known and handled within the individual service layers? Or should they be handled by another layer? For example: I have two service layers for users and clients. I would like to: 1) Create and save a new client 2) Create and save a new user 3) Assign that user to the client All within a single transaction. A simple example might look like this: ``` $userManagementService = new UserManagementService; $newUserData = array(...); $newUser = $userManagementService->create($newUserData); $clientManagementService = new ClientManagementService; $newClientData = array(...); $newClient = $clientManagementService->create($newClientData); $userManagementService->assignUserToClient($newUser, $newClient); ``` Where should transaction logic go?

Original source

Related problems