We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Updating the same model simultaneously

Hello,

I think it's possible I am having the following problem and I wonder whether you have any suggestions how to best prevent this from happening:

Person A loads model X of record nr 1234 and changes the field 'counter' to counter+1 Meanwhile, Person B loads model X of record nr 1234 and changes the field 'counter' to counter+2 However, person A and person B both loaded the same 'original model' with for example counter being 10. This means, person A stores counter = 11 and a bit later, person B seems to store counter = 12. Whereas I would want it to be counter = 13. This of course only happens occassionally.

It probably happens because the database isn't updates like 'counter = counter + 1' but more like 'counter =new_value_of_model_counter'.

What is the best way to deal with this?



77.7k
Accepted
answer

The culprit is the stateless nature of the HTTP protocol.

The only (easy) solution is what you've mentioned: refactor your code to queries instead of model properties, so you can execute counter = counter + 1



3.4k
edited Apr '17

You could call the beforeSave() method in the model. So something like this;

class Robots extends \Phalcon\Mvc\Model
{
    // ....

    public function beforeSave()
    {
         // Grab the most recent record version
         $objNewerRecord = Robots::findbyId($this->getId());
         // Update the counter to what it is in the db +1
         $this->setCounter($objNewerRecord->getCounter()+1);
         // Clear memory
         unset($objNewerRecord);
    }
}

This means you don't need to do anything else when you call $objRobots->save() as beforeSave() is called just before the insert/update.

edited Apr '17

That's still susceptible to parallel updates, unless you wrap it in a transaction.

Also, it is a bad idea performence-wise, if you care about that.

You can generate some hash of model state and check it before update. If hash doen't match, the model instance need to be reinitialization.

Thank you for your reply and solution :) Would PHQL be suitable to do this or can this only be accomplished with raw queries?

The culprit is the stateless nature of the HTTP protocol.

The only (easy) solution is what you've mentioned: refactor your code to queries instead of model properties, so you can execute counter = counter + 1

Thanks for the other ideas as well!

PHQL will also do the trick ;]