Я нахожусь в процессе разработки аукциона, такого как веб-приложение, с использованием Rails 3.1 и MySQL 5.1. Пользователи будут иметь остатки на счетах, поэтому важно, чтобы кто-то не предлагал цену за аукцион, если у него недостаточно средств.
Очевидно, что я буду упаковывать «выигрыш» аукциона в транзакцию, что-то вроде этого:
Транзакция 1:
ActiveRecord::Base.transaction do
a = Account.where(:id=>session[:user_id]).first
# now comes a long part of code with various calculations and other table updates, i.e. time pases
a.balance -= the_price_of_the_item
a.save!
end
Кстати, я использую оптимистическую блокировку, поэтому во всех моих таблицах есть столбец lock_version.
В то время как такая транзакция выполняется, пользователь может с помощью другого ввода разместить другие заявки, следовательно, всякий раз, когда они делают ставку, фрагмент кода проверяет, достаточен ли текущий доступный баланс
То же самое и здесь:
Транзакция 2:
ActiveRecord::Base.transaction do
a = Account.where(:id=>session[:user_id]).first
raise ActiveRecord::Rollback if a.balance < the_price_of_the_bid + Bids.get_total_bid_value_for_user(session[:user_id])
# now process the bid saving
end
Очевидно, мне нужно убедиться, что две транзакции не перекрываются, в противном случае транзакция 2 может считывать баланс, пока транзакция 1 находится в середине обработки, и я получаю отрицательный баланс счета (ставка сохраняется и впоследствии транзакция 1 фиксируется, тогда пользователь, возможно, сделал ставку с денежными средствами, которых у него больше нет).
Следует отметить, что транзакция 2 не вносит никаких изменений в Учетную запись, она просто читает учетную запись. Я предполагаю, что это сводится к вопросу: как предотвратить любые чтения для выбранных операторов SELECT при выполнении транзакции 1.
Как заставить транзакцию 2 ждать завершения транзакции 1? Возможно ли это с оптимистической блокировкой и одним из доступных уровней изоляции транзакций MySQL или мне нужно использовать здесь пессимистическую блокировку? Если пессимистическая блокировка является единственным ответом, добавление
замок!
после прочтения записи счета в каждой из двух транзакций будет достаточно?
Критерии дизайна, конечно,
- Я ищу наиболее эффективное решение, даже если оно означает больше
кодирование.
- согласованность данных имеет первостепенное значение