关于MySQL/PHP中事务(或表锁?)的问题


Questions Regarding Transactions (or table lock?) in MySQL/PHP

我有一个问题看起来很基本,但很难找到最有效的解决方案。

假设我有这个表,KEYS

KEYS
KEY_ID        VALUE        USED
1             123ASD       1
2             ASD234       0
3             123456       0

我想要一个API(这里称为get_key.php),它将访问数据库中使用的最后一个值为used=0,返回JSON格式的密钥以通过ajax解释给用户,然后将该密钥标记为在数据库中使用。

我看到过关于锁表的想法,但我担心的是,当大量用户请求密钥时,会有一个脚本不断地生成密钥并将其插入数据库。

实现这一点的最佳方法是什么,同时仍然可以安全地防止发送重复条目、表锁定导致网页交付的长时间延迟,以及在检索时仍然可以插入?

如果你仍然感到困惑,这里有一个基本的例子。。。

get_key.php

//not real file just pseudo
//(lock table?)
//SELECT VALUE, KEY_ID FROM `KEYS` WHERE USED = 0 LIMIT 1;
//$key = $response['VALUE']
//echo out key in json format
//$key_id = $response['KEY_ID']
//UPDATE `KEYS` SET USED = 0 WHERE KEY_ID = $key_id;
//(unlock table?)

insert_key.php

//$key = $_GET['value']
//(lock tables?)
//INSERT INTO `KEYS` (VALUE) VALUES ($key)
//(unlock tables?)

我知道这种在生产环境中的设置会非常不安全,但尽量简单,这样你就可以正确地理解我的问题。

非常感谢您抽出时间!

使用InnoDB或任何其他支持行级锁的引擎。然后你只需要锁定你正在选择/更新的一行,例如

SELECT VALUE, KEY_ID
FROM `KEYS`
FOR UPDATE  // <--- add this row
WHERE USED = 0 LIMIT 1;
... do other stuff
UPDATE `KEYS`
SET USED = 1
WHERE KEY_ID = xxx;
COMMIT;

MySQL会锁定它找到的记录,然后只有这个特定的DB连接才能修改该记录,直到它被解锁或连接关闭。