【问题标题】:MySQL transaction with accounting application与会计应用程序的 MySQL 事务
【发布时间】:2008-11-15 16:06:29
【问题描述】:

我有一张如下表:

transaction_id
user_id
other_user_id
trans_type
amount

此表用于维护金融类应用的账户交易。

它的复式记账,所以从用户 A 到 B 的转移会在表中插入两行。

1, A, B, Sent, -100
1, B, A, Received, 100

任何帐户的余额都是通过汇总该帐户的交易来计算的。

例如:

select sum(amount) from transactions where user_id=A

锁定资金转移的最佳方式是什么?我当前的代码如下所示:

Start Transaction
Debit the sender's account
check the balance of the sender's account
if new balance is negative then the sender didn't have enough money and rollback
if the balance is positive then credit the receiver and commit

这似乎没有完全按预期工作。我在网上看到很多关于交易的例子,基本上都是:开始、借方、贷方、提交。但是检查发件人之间余额的最佳方法是什么?

我有一些不应该通过的交易。假设一个用户有 3K 的余额,并且两笔交易同时进入 3K,这两个交易都在只有一个应该通过的时候通过。

谢谢

【问题讨论】:

    标签: mysql transactions


    【解决方案1】:

    您使用的是 InnoDB 表还是 MyISAM 表? MySQL 不支持 MyISAM 表上的事务(但如果您尝试使用它们,它不会给您错误)。此外,请确保您的事务隔离级别设置得当,它应该是 SERIALIZABLE,这不是 MySQL 的默认值。

    这个article 有一个很好的例子,它使用与你的例子非常相似的例子来解释不同隔离级别的影响。

    【讨论】:

      【解决方案2】:

      问题在于“用户帐户”的概念“分散”在表中的许多行中。使用当前的表示,我认为您不能“锁定用户帐户”(可以这么说),因此在修改它们时您可以接受竞争条件。

      一种可能的解决方案是拥有另一个带有用户帐户的表,并锁定该表中的一行,因此任何需要修改帐户的人都可以尝试获取锁定,执行操作并释放锁定。

      例如:

      begin transaction;
      update db.accounts set lock=1 where account_id='Bob' and lock=0;
      if (update is NOT successful) # lock wasn't on zero
        {
        rollback;
        return;
        }
      if (Bob hasn't enough funds)
        {
        rollback;
        return;
        }
      
      insert into db.transactions value (?, 'Bob', 'Alice', 'Sent', -3000);
      insert into db.transactions value (?, 'Alice', 'Bob', 'Received',  3000);
      update db.accounts set lock=0 where account_id='Bob' and lock=1;
      
      commit;
      

      ...或类似的东西。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-03
        • 1970-01-01
        • 2017-11-19
        • 2015-09-21
        相关资源
        最近更新 更多