mariadb 处理并发事务期间的帐户余额

kxe2p93d  于 2023-01-05  发布在  其他
关注(0)|答案(1)|浏览(133)

我一直在开发一个应用程序来处理帐户和所有帐户上的交易。
目前,应用程序使用的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列)。

svmlkihl

svmlkihl1#

简单的答案是不要将resulting_amount保存在事务表中,而只是将余额保存在一个单独的表中(主键为account_id)。
或者这样做,然后在事务中更新帐户余额,并将新余额用作要插入的resulting_amount。
您现有的代码只是假设ORDER BY at.date DESC, at.id DESC总是能找到最近插入的记录,而这对于并发请求来说是不成立的。

相关问题