简体   繁体   中英

How can I prevent two users from accessing MySQL table at the same time?

Let's say I got a website which, when visited, shows what is your lucky word today. The problem is that every word can be lucky for only one person so you need to be fast visiting the website. Below is a sample table with lucky words:

+---------------------+
| lucky_word          |
+---------------------+
| cat                 |
| moon                |
| piano               |
| yellow              |
| money               |
+---------------------+

My question is: how can I prevent two (or more) users from accessing that table at one time. I assume that every user reads the first lucky_word from the existing table and the chosen word is deleted immediately so it won't be the next user's lucky word. For instance, I want to avoid cat to be shown to more than one visitor.

Should I solve this using an appropriate MySQL query or some lines in a PHP code or both?

You can use a locking read within a transaction ; for example, using PDO:

$pdo = new PDO('mysql:charset=utf8;dbname='.DBNAME, USERNAME, PASSWORD);

$pdo->beginTransaction();

$word = $pdo->query('SELECT lucky_word FROM myTable LIMIT 1 FOR UPDATE')
            ->fetchColumn();

$pdo->prepare('DELETE FROM myTable WHERE lucky_word = ?')
    ->execute(array($word));

$pdo->commit();

In MySQL you can lock tables, to prevent other sessions reading and/or writing to the table. In the case of WRITE locks, the first session to request the lock will hold the table until it is released, and then the second session will get it until unlocked, and so forth. That way you can be sure that no two sessions are accessing or manipulating the same data at the same time.

Read all about it in the manual:

https://dev.mysql.com/doc/refman/5.6/en/lock-tables.html

How about adding a datestamp to the table updated when that particular word is used?

You could then use the following pseudo sql...

select word from words where lastdate <> [today];
update words set lastdate = today where word = [word];

A quickly method I used for a similar task:

1) create a table "unique_sequence" with just un field: id -> INT AUTOINCREMENT

 CREATE TABLE `erd`.`unique_sequence` (
   `id` INT NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`));

2) when a user arrives on the site:

INSERT INTO unique_sequence VALUES();
SELECT word FROM lucky_word WHERE id = LAST_INSERT_ID();

As The ID that was generated by LAST_INSERT_ID() is maintained in the server on a per-connection basis it should be multi-user safe...

... and so we can be sure that every new user will get a unique ID that match the ones in lucky_word table.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM