yiisoft / yii

Yii PHP Framework 1.1.x
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
4.84k stars 2.29k forks source link

how to save data in Yii and be sure on correct saving? #3963

Closed iblessedi closed 9 years ago

iblessedi commented 9 years ago

Example: we have test table, which has 3 columns: id, watchers, title. We have a code:

$test = Test::model()->findByPk(1);
echo $test->watchers; // 0
$test->title = 'another';
$test->save();

When we call save() ir generates sql query like "UPDATE test SET title='another', watchers='0' WHERE id='1'". SO, seams like everything is okay. But the problem is that if some another process will update watchers variable in the time between findByPk and save in current script, the code will generate wrong value. So:

$test = Test::model()->findByPk(1);
echo $test->watchers; // 0
$test->title = 'another';
//HERE WE HAVE A CODE WHICH PERFORMS FOR 1 SECOND. MEANWHILE ANOTHER PROCESS
// UPDATES TABLE WITH WATCHERS = 1
$test->save();

So, this code will save record's watchers field back to 0. How to overcome this? Why Yii ORM doesn't save only changed values? Why it tries to save all values? Thank you.

Deprecator commented 9 years ago

Yiis ORM doesnt select data before updating it.

Your case is a typical race condition issue.

https://en.wikipedia.org/wiki/Race_condition

I'd suggest you to use transactions where data consistency is important.

iblessedi commented 9 years ago

as for me, the problem is because Yii tries to save all data in the model, only only changed one. Why can't it compare selected data from the db and current state and save only changed values?

samdark commented 9 years ago

Yii 2.0 does it. We aren't going to change it in 1.1 since that would break compatibility.

iblessedi commented 9 years ago

So, we cannot use Yii 1.1 in highload systems? Is there any workarounds?

samdark commented 9 years ago

Transactions, diffs, etc. Depends on the system.

samdark commented 9 years ago

Saving individual fields won't save you from concurrency issues.

iblessedi commented 9 years ago

Why can't I inherit and rewrite the CActiveRecord::save and save only changed attributes?

samdark commented 9 years ago

You can. I'm just saying that it won't be included in 1.x version of Yii.

iblessedi commented 9 years ago

Do you think this will work? Comparing every field's value to it when it was fetched to the db and try saving only if it was saved? Which bugs can I encounter? Any issues? Thanks for helping me!

samdark commented 9 years ago

Check Yii 2.0 for implementation of "dirty attributes". It works exactly how you said. Bugs are type issues mostly such as changing 0 to false or empty string and the fact that everything that comes from form POST requests are always strings.

Implementing it would make concurrency issues less prominent but you'll still have them. For example, the situation of two users editing a blog post text at the same time is still very likely.

If you want to really solve concurrency issues, think about revisions support with automatic content merge (something like git) and manual conflicts handling. Or lock editing while another user is editing. Or, alternatively, accept the fact of these conflicts. But all these solutions depend very much of the application and could not be part of the framework.

iblessedi commented 9 years ago

Successfully implemented behaviour of Yii2 getDirtyAttributes in my Yii 1 app. Thanks for a help.