使用预准备语句的SELECT ... FOR UPDATE不起作用

时间:2013-08-29 08:37:39

标签: php transactions mysqli prepared-statement table-locking

我正在尝试创建一个类似fb的按钮功能(不是facebook api)。 我的网站上有两个按钮:喜欢和不喜欢。 数据库将保存总共喜欢和不喜欢的数量。

这是db表:

id |post_id |like_count
40 |     20 |         0

用户点击按钮时的代码:

$id = 40;
$conn->autocommit(FALSE);
$conn->query("BEGIN;");

//lock the row to prevent race condition
$sql = "SELECT like_count FROM post_like WHERE id = ? LIMIT 1 FOR UPDATE";
$stmt = $conn->prepare($sql);
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->close();

//update the table
$sql = "UPDATE post_like SET like_count = like_count + 1 WHERE id = ? LIMIT 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->close();

$conn->commit();
$conn->autocommit(TRUE);
$conn->close();
//when success, display unlike button to user throught AJAX

以及用户点击时不像按钮的代码:

$id = 40;
$conn->autocommit(FALSE);
$conn->query("BEGIN;");

//lock the row to prevent race condition
$sql = "SELECT like_count FROM post_like WHERE id = ? LIMIT 1 FOR UPDATE";
$stmt = $conn->prepare($sql);
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->close();

//update the table
$sql = "UPDATE post_like SET like_count = like_count - 1 WHERE id = ? LIMIT 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->close();

$conn->commit();
$conn->autocommit(TRUE);
$conn->close();
//when success, display like button to user throught AJAX

这是问题......
like_count的数量从0开始 从理论上讲,如果只有一个人点击按钮,like_count将不会超过1或小于0 (点击按钮 - > - >锁定行 - > like_count + 1->释放行 - >显示不像按钮)
(点击不像按钮 - >锁定行 - > like_count-1->释放行 - >显示按钮)
当我慢慢点击按钮时,我的工作正常,但是,当我继续快速点击按钮时,like_count的数量可以超过2,有时它可以是负数。
我不知道我做错了什么。请帮忙!

3 个答案:

答案 0 :(得分:0)

更新查询中的

$stmt->execute();

以下

$stmt->bind_param('i', $id);

答案 1 :(得分:0)

处理所有按钮的代码。

$amount = (isset($_POST['like'])) ? 1 : -1;
$sql    = "UPDATE post_like SET like_count = like_count + ? WHERE post_id = ?";
$stmt   = $conn->prepare($sql);
$stmt->execute(array($amount,$_POST['id']));

请注意,此表中不需要id列。 post_id没问题

答案 2 :(得分:0)

更改:

$conn->autocommit(FALSE);

要:

$conn->autocommit(TRUE);

更新和插入查询不适用于$conn->autocommit(FALSE);