【问题标题】:Mysql transaction for transferring credit between users用于在用户之间转移信用的Mysql事务
【发布时间】:2012-02-17 06:17:42
【问题描述】:

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

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

【问题讨论】:

    标签: php mysql sql transactions innodb


    【解决方案1】:

    首先,不要为此烦恼:

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

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

    问题2:电源是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 约束(作为触发器实现)确保没有人可以提供比他们拥有的更多的权力。

    【讨论】:

    • @Ali:酷,这就是我们都在这里的原因:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-24
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    • 2013-08-31
    • 1970-01-01
    相关资源
    最近更新 更多