Jump to content

Where to locate transactions


Recommended Posts

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();
Link to comment
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.

Link to comment
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?

Link to comment
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.

Link to comment
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
Link to comment
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.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

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.