MySQL事务与会计应用程序

时间:2008-11-15 16:06:30

标签: mysql transactions

我有一张如下表格:

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完全相同的时间进入,当只有一个时,这两个交易都会通过。

谢谢

2 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:1)

问题是“用户帐户”的概念在表格中的许多行中“分散”。使用当前的表示形式,我认为您无法“锁定用户帐户”(可以这么说),因此您在修改它们时会对竞争条件持开放态度。

一个可能的解决方案是让另一个表包含用户帐户,并在该表中锁定一行,这样任何需要修改帐户的人都可以尝试获取锁,执行操作并释放锁。

例如:

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;

......或类似的东西。