用于在用户之间转移信用的Mysql事务

时间:2012-02-17 06:17:42

标签: 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.这意味着用户将被授予几乎无限的权力(信用)。

1 个答案:

答案 0 :(得分:3)

首先,不要为此烦恼:

  

在运行上述查询集之前,我检查发件人是否有足够的信用来通过SELECT查询进行传输。

这让你对竞争条件持开放态度,无论如何你都要处理。相反,在数据库中设置约束以使其无法进入无效状态。

  

第2期:权力为unsigned int

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

就限制数据而言,通常你会使用像这样的CHECK约束:

check (power >= 0)

但MySQL不支持CHECK约束。但是,您可以编写一个BEFORE INSERT或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发送到数据库。
  6. 事务将确保所有三个操作作为单个单元成功或失败,并且CHECK约束(实现为触发器)确保没有人可以提供比他们更多的权力。