php - PHP/MySQL 中的原子有界增加

标签 php mysql

我有 2 张 table :

t1:

+----+--------+------+
| id | n_data | type |
+----+--------+------+
|  1 |     10 |    1 |
+----+--------+------+

t2:

+-----+------+
| type | max |
+------+-----+
|    1 |  50 |
+------+-----+

我想做的是:当用户选择t1的一个元素时,比如id = 1,我增加相应的n_data 增加 1,除非它已达到 t2 中相应的值 max(使用 join t1.type = t2.类型)。 在这种情况下,我会警告用户。

我有:

$result = $conn->query("SELECT t1.n_data, t2.max 
                        FROM t1, t2 
                        WHERE t1.type = t2.type AND t1.id = " . $id);
$row = $result->fetch_assoc();
if ($row["n_data"] < $row["max"]) {
  $conn->query("UPDATE t1 
                SET n_data = n_data + 1 
                WHERE id = " . $id);
}
else {
  echo "We have reached the max!";
}

显然,我这里有一个竞争条件。其他人可以在两条 MySQL 指令之间增加 n_data

如何将两个查询合并为一个,或者使它们成为原子查询?

最佳答案

我想我会使用 where 子句中的 max 更新表格:

update t1
set n_data=n_data+1 
where 
  id = :id and
  n_data < :max;

之后,您可以检查受影响的行。如果为0,则表示已达到最大值,更新失败。

但是,当然,最好不要将 max 作为参数传递,而是内联查询:

update t1
set n_data=n_data+1 
where 
  id = :id and
  n_data < (select max from t2 where t2.type=t1.type);

整个 PHP 代码将非常简单。只需运行此更新,然后检查受影响的行 == 0 并在这种情况下回显错误消息。像这样的事情:

$stmt = $conn->prepare("
    update t1
    set n_data=n_data+1
    where 
      id = ? and
      n_data < (select max from t2 where t2.type=t1.type)");
$stmt->bind_param("i", $id);
$stmt->execute([$id]);

if ($stmt->num_rows === 0) {
  echo "We have reached the max!";
}

关于php - PHP/MySQL 中的原子有界增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55123168/

相关文章:

php - 如何使用间隔将mysql日期字段与今天+30天进行比较

mysql - Mysql Group_concat 与 concat

php - 如何通过 PHP/MySQL 替换第一个点之后的所有文本

php - 如何在 PHP 中将日期格式化为意大利语?

PHP前端用户队列

PHP 函数定义,空参数

mysql - 如何选择日期并忽略时间

php - 我应该创建一个对象还是使用数组?

php - PDO 获取未返回所有行

php - PHP 中 SQL 的语法错误