PHP when database update encounters concurrency, a small pit

Source: Internet
Author: User

There is a small item to answer the table with the following fields:

ID User ID
Times answers
Questions answers the question ID, which is a string of PHP serialize ()

When the user answers the question like the backend submission results, the built post package is as follows:

{    ' id ': 1,    ' QuestionID ': 38}

The background logic is as follows:

$user = User::findfirst ("id =? 1", Array (' ID ' =>$_post[' id ')));//get user Model $questions = unserialize ($user->questions );//deserialization $questionid = (int) $_post[' QuestionID '];//topic idif (In_array ($questionid, $questions)) {//To determine if the user replied, If not answered, add the title ID to the questions field    $questions [] = $questionid;    $user->times + = 1;//Statistical answer    $user->questions = serialize ($questions);//Serialization Questions    $user->save () ;//update} else {    exit (' Sorry, you have already answered this question);}

It seems that the process is not a problem ah, the user each time the submission will be read their own data, testing whether to answer the question, answer the direct exit.

but there is a problem:
When the event was launched the next day, the background data found that a user's times and questions records did not match, showing times=120 count (unserialize (questions)) = 17.
At that time very strange, the code normal process is no problem, the card for a half-day, has not thought out how the user caused this data, until just now, finally enlightened, as the topic said, the problem in the concurrency , the user may write his own script or the use of third-party tools to simulate the POST request, and using techniques such as multithreading to create concurrent requests, let's simulate the concurrency process:

The user initiates two requests at the same time, PHP also allocates two processes to handle, in front of the two processes almost simultaneously executes this line of code:

$user = User::findfirst ("id =? 1", Array (' ID ' =>$_post[' id '));//Get User model

At this point the $user data in the two processes is the same, let's assume that at this point the value of $user->questions is {.}.

Suppose that two requests were built with a post packet of:

{    ' id ': 1,    ' QuestionID ': 3}

And

{    ' id ': 1,    ' QuestionID ': 4}

So when the code executes to:

In_array ($questionid, $questions)

is actually returning false when the
They launched the $user->save (), respectively, want to add 3 and 4 into questions, note that this time questions in the database is the value of {"}, and the SQL statement is executed, That is, the database has performed two update operations sequentially, first changing the value of questions to {x-i}, then the second save () is executed and changed to {1,2,4}, two times is incremented by 1, so the final result is:
Times questions
4 {1,2,4}

At this time, if the user continues to submit ' QuestionID ': 3, then change to:
Times questions
5 {1,2,3,4}

This is a two concurrency scenario, which can cause times to be more than the number of questions 1
What if we simulate 10 concurrency? Don't want to forget.

Since the problem has appeared, or to solve Ah, the first thought of using InnoDB row-level lock, unfortunately, the table is MyISAM ...

The final solution is implemented by an exclusive lock on the operating system file, and a friend in front of the screen is interested to see:
http://my.oschina.net/cxz001/blog/281130

PHP when database update encounters concurrency, a small pit

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.