Я разрабатываю приложение, которое обрабатывает счета и транзакции, выполненные над этими учетными записями.Эффективно обрабатывать текущий баланс счета
В настоящее время таблицы виды использования приложения моделируются следующим образом:
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 и, в счета таблице, обновляет столбец 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 время обновление строк на счет стол. Эти взаимоблокировки налагают серьезную штрафную санкцию на применение, поскольку она заставляет транзакции перерабатываться, когда возникают взаимоблокировки в базе данных.
Как я могу эффективно обрабатывать текущий баланс для счетов? Текущий баланс необходим для авторизации/отказа от новых транзакций и используется в различных отчетах.
звучит хорошо, но один вопрос: не удалось ли поле result_amount быть неверным? Скажем, транзакция X и Y одновременно считывают текущий баланс и вставляют свои строки account_transaction одновременно. Хотя баланс будет правильным после обеих транзакций, не будет result_amount ошибочным для одной из строк? –
@JoshNankin Мой ответ сосредоточился на 'current_balance', и он не будет работать так хорошо, если вам понадобится действительно« serial »' result_amount', как вы отметили. Попробуйте изменить порядок операций: сначала обновите 'current_balance', затем просто скопируйте новый баланс в новый' result_amount'. InnoDB должен блокировать UPDATE, эффективно сериализуя транзакции (на одной и той же «учетной записи» - другие учетные записи могут продолжаться одновременно) и избегать аномалии на INSERT. Это должно быть достаточно быстро - я предлагаю вам измерить, прежде чем пытаться реализовать оптимистичную схему блокировки. –