我一直在开发一个应用程序来处理帐户和所有帐户上的交易。
目前,应用程序使用的MariDB数据库表建模方式如下:
account_transaction中的ID列是主键,它将自动递增
account_transaction
+------+-------------+----------------------+---------+------------------+-----+
| id | account_id | date | value | resulting_amount | ... |
+------+-------------+----------------------+---------+------------------+-----+
| 101 | 100 | 03/may/2012 10:13:33 | 2000 | 2000 | ... |
| 102 | 100 | 03/may/2012 10:13:33 | 500 | 2500 | ... |
| 103 | 100 | 03/may/2012 10:13:34 | -1000 | 1500 | ... |
| 104 | 200 | 03/may/2012 10:13:35 | 1300 | 1300 | ... |
| 105 | 200 | 03/may/2012 10:13:36 | 200 | 1500 | ... |
| 106 | 200 | 03/may/2012 10:13:37 | -500 | 1000 | ... |
+------+-------------+----------------------+---------+------------------+-----+
将金额300贷记到account_id(100)的查询是
INSERT INTO account_transaction (account_id,date, value, resulting_amount)
VALUES (100, NOW(), 300, COALESCE((SELECT at.resulting_amount
FROM account_transaction at
WHERE at.account_id = 100
ORDER BY at.date DESC, at.id DESC
LIMIT 1), 0) + 300)
将金额300记入account_id(100)借方的查询是
INSERT INTO account_transaction (account_id,date, value, resulting_amount)
VALUES (100, NOW(), -300, COALESCE((SELECT at.resulting_amount
FROM account_transaction at
WHERE at.account_id = 100
ORDER BY at.date DESC, at.id DESC
LIMIT 1), 0) - 300)
我正在使用子查询来查找最新的余额,同时插入新的交易。我已经使用合并,如果没有交易的帐户。
我本可以单独运行下面的子查询来查找帐户的当前余额并将其用于新事务,但问题是多个并发事务阅读相同的余额,这会导致帐户余额不一致,给公司带来损失。
SELECT at.resulting_amount
FROM account_transaction at
WHERE at.account_id = 100
ORDER BY at.date DESC, at.id DESC
LIMIT 1
插入查询方法中的子查询能够在并发请求少于50时处理余额差异。
如果事务处理数大于50,则有时会出现余额差异。余额差异示例:如果帐户余额为1000,并且2个并发事务处理要借记100,则两个事务处理的resulting_amount将为900,这是不正确的。
请建议在放置大量并发事务处理时处理余额差异的更好方法。如果要建议锁方法,请使用列层锁(锁定account_id列)。
1条答案
按热度按时间svmlkihl1#
简单的答案是不要将resulting_amount保存在事务表中,而只是将余额保存在一个单独的表中(主键为account_id)。
或者这样做,然后在事务中更新帐户余额,并将新余额用作要插入的resulting_amount。
您现有的代码只是假设
ORDER BY at.date DESC, at.id DESC
总是能找到最近插入的记录,而这对于并发请求来说是不成立的。