How to make sure there is no race condition in MySQL database when incrementing a field?

社会主义新天地 提交于 2019-11-26 21:59:28

Here's 3 different approaches:

Atomic update

update table set tries=tries+1 where condition=value;

and it will be done atomically.

Use transactions

If you do need to first select the value and update it in your application, you likely need to use transactions. That means you'll have to use InnoDB, not MyISAM tables. Your query would be something like:

BEGIN; //or any method in the API you use that starts a transaction
select tries from table where condition=value for update;
.. do application logic to add to `tries`
update table set tries=newvalue where condition=value;
END;

if the transaction fails, you might need to manually retry it.

Version scheme

A common approach is to introduce a version column in your table. Your queries would do something like:

select tries,version from table where condition=value;
.. do application logic, and remember the old version value.
update table set tries=newvalue,version=version + 1 where condition=value and version=oldversion;

If that update fails/returns 0 rows affected, someone else has updated the table in the mean time. You have to start all over - that is, select the new values, do the application logic and try the update again.

Use a single statement instead of two. A single UPDATE statement that performs both the read and the write will be atomic and won't conflict with another simultaneous update.

UPDATE table SET tries = tries + 1 WHERE ...

Or you can use transactions to make the two operations atomic.

BEGIN
SELECT ...
UPDATE ...
COMMIT

Or, more primitively, lock the table while you're reading/writing to it.

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