PHP and Concurrency

不羁的心 提交于 2021-02-17 16:40:35

问题


I've been doing some web development work in PHP recently which has led me to study up on the language in general. So far I have not needed to use it to interact with a database, but I know it provides a lot of convenient functions for doing so.

Although I know basic SQL and have worked with basic manipulation of data in a database, I don't understand how web developers who base their websites around PHP/Javascript/SQL are able to manage users modifying the same data at the same time.

For example, lets say you have a blackjack website which divides users into one of two teams when they sign up. Every time a user wins a game, a portion of their winnings is added to a running total for that team.

So lets say the pseudo code for the function that does this looks something like this:

... 
$total = mysql_query("SELECT score FROM team1");
$total = $total + $mytotal;
mysql_query("UPDATE team1 SET score='".$total."'");
...

If two players are playing at the same time, it's very possible that they will both call SELECT before the other one has a chance to increment and update the table, so one users changes will be immediately overwritten.

My question is, how does one avoid this? Is it done using PHP at the code level, or are there features provided by whatever database you are using that help to prevent this?

I've been doing some research, and it seems that PHP does provide a semaphore mechanism, and I've also noticed that mysql offers a LOCK table feature. However, I'm not sure which of these, if either, is used in practice.


回答1:


IF your real world problem is bigger than this simple example, you should use a transaction in conjunction with lock tables to make sure users don't overwrite each other.




回答2:


Keep the logic at the DB, those semantics have mostly been solved for you.

update teams
set score = score + 1
where team_id = 1

.. or whatever score and whatever team number.




回答3:


Major databases are designed to handle such situations.

When using MySQL, the InnoDB storage engine has the row-locking feature, which locks the row that is being written to. So, any update request that is for the same row will wait until the previous operation on the row completes.

If you use MyISAM storage engine, that locks the whole table when a row is being updated. That creates a choke on the server when multiple players simultaneously push update requests. So it is all about what database and particularly what storage engine you are using for the purpose.




回答4:


I agree with Xepochs answer, don't introduce concurrency concerns unless you absolutely need to. For a great answer regarding different locking strategies see here.




回答5:


The database manages concurrent locking and ensures that changes are made atomically. This is a benefit of using a database that supports ACID transactions.

In most cases changes are quick enough that lock contention is minimal. But it can still happen, so you need to check for error status returned after you execute an SQL query. The mysql_query() function returns FALSE if there's a problem.

Then you get to figure out the cause (update conflict, insufficient permissions, SQL syntax error, etc.) by calling mysql_errno(). See http://dev.mysql.com/doc/refman/5.1/en/error-messages-server.html for MySQL error code reference.




回答6:


I can't believe that none of the above answers are pointing out that you may be running into a design flaw.

Yes all the answers are correct, mysql can handle racing conditions and mutually exclusive access to tables.

However, if you come across a problem like this it is probably time to re-think your design. Why are you not keeping a user id for whoever added a portion of their winnings? You could then have a:

    INSERT INTO team1(userid, amount) VALUES(32, 100);
    SELECT SUM(amount) FROM team1
or
    REPLACE INTO team1 SET amount = $total

But if it was me, I wouldn't even bother. I would simply set_cookie(team_score, team_score+amount) and keep everything client side. When I would want to read the score I would fire an AJAX request to read or write to the server and still update the client interface asynchronously. Since you point out that your web development is basic I recommend that you have a look at the jQuery framework for asynchronous client-server communication as it is by far the easiest way to achieve this.

EDIT: And for the problem of updating everyone's UI when another player adds an amount to the score, I suggest you look into backbone.js which tights your data model nicely to the players' client so that they get immediate updates when the score changes.




回答7:


Databases have built in concurrency control, for example you can read about postgres concurrency control here. If I am right, the default settings by pgsql are optimistic locking and read committed transaction isolation, which means that every transaction is aware of the changes done by other uncommitted transactions.

In you case these settings are okay, so you can do simply UPDATE team1 SET score = score + mytotal, and the database will handle well the concurrency issues.

If you have a longer select - update issue, then you can lock the rows manually by the first select with a SELECT FOR UPDATE query.

These are the best practices currently...



来源:https://stackoverflow.com/questions/1712860/php-and-concurrency

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!