我一直在开发一个处理这些帐户的帐户和交易的应用程序。
目前,应用程序使用的表格按以下方式建模:
account +----+-----------------+---------+-----+ | id | current_balance | version | ... | +----+-----------------+---------+-----+ | 1 | 1000 | 48902 | ... | | 2 | 2000 | 34933 | ... | | 3 | 100 | 103 | ... | +----+-----------------+---------+-----+ account_transaction +------+-------------+----------------------+---------+------------------+-----+ | id | account_id | date | value | resulting_amount | ... | +------+-------------+----------------------+---------+------------------+-----+ | 101 | 1 | 03/may/2012 10:13:33 | 1000 | 2000 | ... | | 102 | 2 | 03/may/2012 10:13:33 | 500 | 1500 | ... | | 103 | 1 | 03/may/2012 10:13:34 | -500 | 1500 | ... | | 104 | 2 | 03/may/2012 10:13:35 | -50 | 1450 | ... | | 105 | 2 | 03/may/2012 10:13:35 | 550 | 2000 | ... | | 106 | 1 | 03/may/2012 10:13:35 | -500 | 1000 | ... | +------+-------------+----------------------+---------+------------------+-----+
每当应用程序处理新事务时,它会在 account_transaction 中插入一个新行,并在 account 表中更新列 current_balance 存储帐户的当前余额和用于乐观锁定的列版本。 如果乐观锁定有效,则提交事务,如果事务没有回滚。
作为一个粗略的例子,当处理事务102时,应用程序完成了 跟随伪SQL / JAVA:
set autocommit = 0; insert into account_transaction (account_id, date, value, resulting_amount) values (2, sysdate(), 550, 2000); update account set current_balance = 2000, version = 34933 where id = 2 and version = 34932; if (ROW_COUNT() != 1) { rollback; } else { commit; }
但是,某些帐户非常活跃并且会收到许多同时发生的事务,这会导致MySQL在更新 account 表中的行时出现死锁。这些死锁会对应用程序造成严重的性能损失,因为它会导致在数据库发生死锁时重新处理事务。
如何有效处理帐户的当前余额?授权/拒绝新交易需要当前余额,并在各种报告中使用。
答案 0 :(得分:3)
如何有效处理帐户的当前余额?
我认为整个模型都是过度设计的。
通过version
放弃乐观锁定并简单地......
UPDATE account SET current_balance = current_balance + value WHERE id = ...
...在插入新account_transaction
的事务的 end 应该足够快。为了数据完整性,请考虑将此项置于account_transaction
1 上的AFTER INSERT触发器中。
SELECT ... FOR UPDATE
。 1 但要注意不要过早触发它 - 只有在完全"煮熟时才插入新的account_transaction
,并且不要(例如)早期插入,但稍后更新resulting_amount
。