php - 用户间信用转移的Mysql事务

标签 php mysql sql transactions innodb

我有一个简单的电力系统,因为用户可以互相借用:

mysql_query("INSERT INTO power (sender, receiver, amount)
    VALUES ('$sender', '$receiver', '$amount')");
mysql_query("UPDATE users SET power=power-$amount WHERE user_id='$sender'");
mysql_query("UPDATE users SET power=power+$amount WHERE user_id='$receiver'");

在运行上述一组查询之前,我通过 SELECT 查询检查发件人是否有足够的信用来转账。

问题1:我认为,最好将这四个查询都放在一个Transaction中;因为 InnoDB ACID 将保证更安全的性能。这样做的最佳交易是什么?

问题 2: 幂为 unsigned int。如果万一(即使不太可能),用户没有足够的信用 power-$amount 不会设置为 0;相反,它将循环通过 int() 的最大值,即 4294967295。这意味着用户将被授予几乎无限的权力(信用)。

最佳答案

首先,不要理会这个:

I check if the sender has enough credit to transfer by a SELECT query before running the above-mentioned set of queries.

这会让您面临无论如何都必须处理的竞争条件。相反,在您的数据库中设置约束以使其不可能进入无效状态。

Issue 2: power is unsigned int.

也不要那样做,没必要。一个 4 字节的有符号整数应该在正面有足够的空间;如果没有,您可以切换到带符号的 8 字节整数。您需要一个有符号值的原因是它使完整性检查变得相当容易:如果余额低于零,则说明有问题。如果您使用无符号值,则必须保留 4294967295-n (对于某些 n )检测下溢和溢出而不是简单的 < 0 .

就约束数据而言,通常您会使用如下 CHECK 约束:

check (power >= 0)

但 MySQL 不支持 CHECK 约束。但是,您可以编写一个 BEFORE INSERT OR UPDATE 触发器来检查 new.power >= 0raise an exception如果不是。

现在你有一个 users不允许无效的表 power值,所以我们完成了问题 2。

关于问题 1:交易。是的,您绝对想使用 transaction为转移。您需要这样的序列:

  1. start transaction
  2. INSERT INTO power (sender, receiver, amount) VALUES ('$sender', '$receiver', '$amount')
  3. UPDATE users SET power=power-$amount WHERE user_id='$sender'
  4. UPDATE users SET power=power+$amount WHERE user_id='$receiver'
  5. “检查触发器”是否有任何错误?
    • 如果有则发送 rollback到数据库并告诉用户出了什么问题。
    • 如果没有,请发送 commit到数据库。

交易将确保所有三个操作作为一个整体要么成功要么失败,并且 CHECK 约束(作为触发器实现)确保没有人可以放弃比他们拥有的更多的权力。

关于php - 用户间信用转移的Mysql事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9323764/

相关文章:

javascript - jQuery AJAX POST 未触发

php - 如何检查 mysql 表列是否存在?

PHP 搜索脚本无法正确返回页面

mysql - 插入忽略多列数据唯一

php - 无法使用sql删除表中的数据

php - 使用 'OR condition' 的 Doctrine FindBy 方法?

javascript - jQuery AJAX 调用在传递 Rgraph 图像数据时返回 403 禁止错误

MySql:我需要提交 SET SESSION TRANSACTION 吗?

android - 在 SQLite 数据库中加入 3 个表

mysql - 在 mysql 表之间查找丢失的 ID