我一直在开发一个应用程序来处理帐户和通过这些帐户进行的交易。
目前,应用程序使用的表按以下方式建模:
帐户 +----+-----------------+---------+-----+ | 编号 | 当前余额 | 版本 | ... | +----+-----------------+---------+-----+ | 1 | 1000 | 48902 | ... | | 2 | 2000 | 34933 | ... | | 3 | 100 | 103 | ... | +----+-----------------+---------+-----+ account_transaction +--------+-------------+----------+----- --+------------------+--+ | 编号 | account_id | 日期 | 价值 | 结果金额 | ... | +--------+-------------+----------+----- --+------------------+--+ | 101 | 1 | 2012 年 5 月 3 日 10:13:33 | 1000 | 2000 | ... | | 102 | 2 | 2012 年 5 月 3 日 10:13:33 | 500 | 1500 | ... | | 103 | 1 | 2012 年 5 月 3 日 10:13:34 | -500 | 1500 | ... | | 104 | 2 | 2012 年 5 月 3 日 10:13:35 | -50 | 1450 | ... | | 105 | 2 | 2012 年 5 月 3 日 10:13:35 | 550 | 2000 | ... | | 106 | 1 | 2012 年 5 月 3 日 10:13:35 | -500 | 1000 | ... | +--------+-------------+----------+----- --+------------------+--+
每当应用程序处理一个新事务时,它都会在account_transaction中插入一个新行,并且在account表中,它会更新存储帐户当前余额的列current_balance以及用于乐观锁定的列版本。如果乐观锁定有效,则提交事务,否则回滚事务。
作为一个粗略的例子,在处理事务 102 时,应用程序执行了以下伪 SQL/JAVA:
设置自动提交 = 0; 插入 account_transaction (account_id、日期、值、结果金额) 价值观 (2, sysdate(), 550, 2000); 更新帐户集 current_balance = 2000, 版本 = 34933 在哪里 id = 2 和 版本 = 34932; if (ROW_COUNT() != 1) { 回滚; } 别的 { 犯罪; }
但是,某些帐户非常活跃,并且会同时接收许多事务,这会导致 MySQL 在更新帐户表中的行时出现死锁。这些死锁给应用程序带来了严重的性能损失,因为当数据库发生死锁时,它会导致重新处理事务。
如何有效地处理账户的当前余额?当前余额用于授权/拒绝新交易,并用于各种报告。