English 中文(简体)
PHP and Concurrency
原标题:

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.

最佳回答

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.

问题回答

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.

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.

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.

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.

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.

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...





相关问题
what is wrong with this mysql code

$db_user="root"; $db_host="localhost"; $db_password="root"; $db_name = "fayer"; $conn = mysqli_connect($db_host,$db_user,$db_password,$db_name) or die ("couldn t connect to server"); // perform query ...

Users asking for denormalized database

I am in the early stages of developing a database-driven system and the largest part of the system revolves around an inheritance type of relationship. There is a parent entity with about 10 columns ...

Easiest way to deal with sample data in Java web apps?

I m writing a Java web app in my free time to learn more about development. I m using the Stripes framework and eventually intend to use hibernate and MySQL For the moment, whilst creating the pages ...

join across databases with nhibernate

I am trying to join two tables that reside in two different databases. Every time, I try to join I get the following error: An association from the table xxx refers to an unmapped class. If the ...

How can I know if such value exists in database? (ADO.NET)

For example, I have a table, and there is a column named Tags . I want to know if value programming exists in this column. How can I do this in ADO.NET? I did this: OleDbCommand cmd = new ...

Convert date to string upon saving a doctrine record

I m trying to migrate one of my PHP projects to Doctrine. I ve never used it before so there are a few things I don t understand. In my current code, I have a class similar to this: class ...

热门标签