在被另一个伴随请求读取之前更新行 MySQL
Update row before being read by another concomitant request MySQL
我正在编写一个 PHP 页面,为每个请求提供一个响应,该响应是来自 table 的一个名为 TOKENS 的值,每个检索到的令牌不得提供给其他请求,所以我' m 将名为“used”的字段更新为 1,以便使用“WHERE used=0”条件无法再次检索该行。
<?php
// read an un used token
$sql = "SELECT tokenvalue FROM TOKENS WHERE used=0 ORDER BY ID DESC LIMIT 1;";
$result = $conn->query($sql);
if (!$result) {
die('Invalid query: ' . $conn->error);
}
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
// set row status to used so it can't be retrieved again
$sql = "UPDATE TOKENS SET used=1;";
$conn->query($sql);
echo ($row["tokenvalue"]);
break;
}
}
?>
我面临的问题是,当我通过一次发送 50 个请求来测试脚本时,许多响应返回与其他响应相同的标记,这意味着它们交织在一起,一些请求在更新之前检索了行第一个请求获得同一行。这是一些请求的输出,粗体哈希值是重复的。
79835adf60b70abd4046b4ca3d3db74c
2f44bfa1cd1d66e4da39b7242e88ede1 2f44bfa1cd1d66e4da39b7242e88ede1 2f44bfa1cd1d66e4da39b7242e88ede1 4320f3a5273b493258ba66db4028fcc2 79835adf60b70abd4046b4ca3d3db74c 9d3cb74140368befbe6fd9dc0ca209a1 47a8e01fec82a44af3b1bd63f3e77816 47a8e01fec82a44af3b1bd63f3e77816 47a8e01fec82a44af3b1bd63f3e77816 2a9ae219d2d57f9988caff3baf48b9b3
我在Whosebug上搜索过,但没有发现类似的问题。
如何让一个请求只读一次行?
我找到了解决方案,感谢评论的人,在 select 请求中单独使用 FOR UPDATE 是不够的, SELECT 和 UPDATE 必须包含在事务中,像这样:
<?php
// Begin transaction
$conn->begin_transaction();
$sql = "SELECT tokenvalue FROM TOKENS WHERE used=0 ORDER BY ID DESC LIMIT 1;";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
// set row status to used so it can't be retrieved again
$sql = "UPDATE TOKENS SET used=1;";
$conn->query($sql);
echo ($row["tokenvalue"]);
break;
}
}
// finish transaction
$conn->commit();
?>
我正在编写一个 PHP 页面,为每个请求提供一个响应,该响应是来自 table 的一个名为 TOKENS 的值,每个检索到的令牌不得提供给其他请求,所以我' m 将名为“used”的字段更新为 1,以便使用“WHERE used=0”条件无法再次检索该行。
<?php
// read an un used token
$sql = "SELECT tokenvalue FROM TOKENS WHERE used=0 ORDER BY ID DESC LIMIT 1;";
$result = $conn->query($sql);
if (!$result) {
die('Invalid query: ' . $conn->error);
}
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
// set row status to used so it can't be retrieved again
$sql = "UPDATE TOKENS SET used=1;";
$conn->query($sql);
echo ($row["tokenvalue"]);
break;
}
}
?>
我面临的问题是,当我通过一次发送 50 个请求来测试脚本时,许多响应返回与其他响应相同的标记,这意味着它们交织在一起,一些请求在更新之前检索了行第一个请求获得同一行。这是一些请求的输出,粗体哈希值是重复的。
79835adf60b70abd4046b4ca3d3db74c 2f44bfa1cd1d66e4da39b7242e88ede1 2f44bfa1cd1d66e4da39b7242e88ede1 2f44bfa1cd1d66e4da39b7242e88ede1 4320f3a5273b493258ba66db4028fcc2 79835adf60b70abd4046b4ca3d3db74c 9d3cb74140368befbe6fd9dc0ca209a1 47a8e01fec82a44af3b1bd63f3e77816 47a8e01fec82a44af3b1bd63f3e77816 47a8e01fec82a44af3b1bd63f3e77816 2a9ae219d2d57f9988caff3baf48b9b3
我在Whosebug上搜索过,但没有发现类似的问题。 如何让一个请求只读一次行?
我找到了解决方案,感谢评论的人,在 select 请求中单独使用 FOR UPDATE 是不够的, SELECT 和 UPDATE 必须包含在事务中,像这样:
<?php
// Begin transaction
$conn->begin_transaction();
$sql = "SELECT tokenvalue FROM TOKENS WHERE used=0 ORDER BY ID DESC LIMIT 1;";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
// set row status to used so it can't be retrieved again
$sql = "UPDATE TOKENS SET used=1;";
$conn->query($sql);
echo ($row["tokenvalue"]);
break;
}
}
// finish transaction
$conn->commit();
?>