Jump to content
Sign in to follow this  
NotionCommotion

Where to locate transactions

Recommended Posts

Posted (edited)

Previously, I've used them in the model/mapper (still a little fuzzy on the difference), but doing so reduce my ability to reuse code, so now I think it should be higher up at the service/controller.  But this level doesn't know if the queries will be atomic, so it seems every call to the mapper must be wrapped with beginTransaction/rollBack/commit.

 

Where should they be located?

 

If at a higher level, what is the best way to minimize code?  Was thing of something like the following.  I don't think doing it above the service is appropriate as it is too limiting.

 

Thanks

 

class SomeService{
    public function someAction(){
        $this->doTransation(function(){$this->callModel(123);});
    }

    protected function doTransation($f){
        echo("beginTransaction\n");
        try {
            $f();
            echo("commit\n");
        } catch (\PDOException $e) {
            echo("rollBack\n");
            throw($e);
        }
    }

    protected function callModel($f){
        echo("call model\n");
    }
}
$service=new SomeService();
$service->someAction();
Edited by NotionCommotion

Share this post


Link to post
Share on other sites

Somewhere in the call stack between the user and the database will (should) be a point where the code knows that it is dealing with the database and that it will be executing multiple queries. It's the place where all the required pieces of work are coordinated to work together to get the end result. If you don't have such a place then you should refactor a bit so that there is one.

That's where the transactions are set up.

 

$f() is apparently where the main work would be. That's probably where the transaction should happen. It could delegate work off to other places, but still $f would be the one that knows what's happening. Not in the service because, while it may know the database is involved, it doesn't know there are multiple queries - it only has the one function call.

Share this post


Link to post
Share on other sites
Thanks requinix,
 
Assuming a service is only called once from an action (maybe a big assumption), then someAction() is where the work is really performed, and I could have just done:
 
    public function someAction(){
        echo("beginTransaction\n");
        try {
            echo("call model\n");
            echo("commit\n");
        } catch (\PDOException $e) {
            echo("rollBack\n");
            throw($e);
        }
    }
As I expect you know, $f was just my cute attempt to reduce script.
 
If multiple services are called, then I expect I should do this:
$app->post('bla/bla/ble', function (Request $request, Response $response) {
    echo("beginTransaction\n");
    try {
        $rs=$this->get('SomeService')->someAction($request->getParsedBody());
        $rs=$this->get('SomeOtherService')->someAction($request->getParsedBody());
        echo("commit\n");
    } catch (\PDOException $e) {
        echo("rollBack\n");
        throw($e);
    }
});

 

But for both these cases, assuming I didn't write the model or if I did I forgot what I wrote, I need to arbitrarily use transactions whether the are really needed or not.

 

No?

Share this post


Link to post
Share on other sites

I think it's too abstract for its own good. Not just your question but the architecture.

 

You have these two service things that each do their own thing that you don't really know much about. Do they work with the database? Probably. But what do they do? Will they stop after one query? Does one make database changes that the other implicitly depends on? Must one always execute before the other? If the first one succeeds and the second fails, does the first need to know about it and potentially take action beyond simply reverting its changes? Or are they unrelated and it's just that they both need whatever they do at the same time, and must both be successful for it to matter?

 

In your shoes I'd be tempted to rewrite both into one service. Or make a new service that copies from both. Whatever so long as there is a single point of responsibility for the sum of actions that are required. Which brings me back to that being the place where transactions should be.

Of course it could be that's what you have there... It feels more like a controller and the two things are models. I don't know.

 

But as a quick solution, yes: that code would be where the transaction is. It doesn't know for sure that the database is involved, or that there will be multiple queries (beyond presumably one for each dependent service), but at least it is where the work is coordinated.

Share this post


Link to post
Share on other sites
Thanks requinix,
 
I agree that the question and especially the architecture is too abstract.
 
Your remarks about the two service things were right on.  Most of the time, a decent ux can have a single clear point between the call stack and database.  For instance, one action to first create a bar chart which does not have any series or categories, and later a second action to add a series or category to the chart.  But to create a gauge chart, the user will want to create both the chart plus add a single series to it as a single action.  I think I will attempt to limit these occurrences and handle them on a case by case basis.
 

Of course it could be that's what you have there... It feels more like a controller and the two things are models. I don't know.

 

Please elaborate on this.
 
Thanks

Share this post


Link to post
Share on other sites

Nevermind. I was thinking about the original code where you had a class named SomeService and combining it with the later code that showed the SomeService and SomeOtherService, and the result of that was you having one service that calls other services. But you don't actually have that.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.