Обновление баланса аккаунта с помощью mysql - PullRequest
1 голос
/ 12 января 2012

У меня есть поле в таблице User, в котором хранится баланс аккаунта для пользователя.Пользователи могут выполнять множество действий с моим сервисом, что приведет к быстрым изменениям их баланса.

Я пытаюсь использовать сериализуемый уровень изоляции mysql, чтобы убедиться, что несколько действий пользователя не обновят значение неправильно.(Действие A и действие B одновременно хотят вычесть 1 баланс из баланса.) Однако я получаю много тупиковых ошибок.

Как мне сделать это правильно, не получая все эти тупики, и при этом сохраняяполе баланса обновлено?

простая схема: у пользователя есть идентификатор и баланс.

я использую доктрину, поэтому я делаю что-то вроде следующего:

$con->beginTransaction();
$tx = $con->transaction;
$tx->setIsolation('SERIALIZABLE');

$user = UserTable::getInstance()->find($userId);
$user->setBalance($user->getBalance() + $change);
$user->save();
$con->commit();

1 Ответ

0 голосов
/ 12 января 2012

Хорошая идея - сначала попытаться использовать сериализуемый уровень изоляции в вашей транзакции. Это означает, что вы по крайней мере знаете, что такое переход, и что уровень изоляции является одной из самых больших проблем.

Обратите внимание, что сериализуемый на самом деле не настоящая надежность. Подробнее об этом на этом предыдущем ответе , когда у вас будет время прочитать его: -).

Но самая важная часть заключается в том, что вы должны учитывать, что автоматические откаты для вашей транзакции из-за неудачной сериализуемости являются нормальным фактом, и что правильное решение состоит в том, чтобы построить приложение так, чтобы транзакции могли завершиться неудачей и должны быть воспроизведены.

Одно простое решение, и для учета вещей мне нравится это простое решение, так как мы можем предсказать все факты, без каких-либо неожиданностей, поэтому одним из решений является блокировка таблицы . Это не изящное и элегантное решение, без блокировок уровней строк, просто простые блокировки больших таблиц (и всегда в том же порядке). После этого вы можете выполнять свои действия в качестве одиночного игрока, а затем снимать блокировки. Не многопользовательский параллелизм в строках таблиц, никакие магические блокировки в следующем ряду не дают ошибок (см. Предыдущую ссылку). Это, безусловно, замедлит ваши операции записи, но если все выполнят блокировки таблиц в одном и том же порядке, вы получите только проблемы с тайм-аутами блокировок, без тупиков и без «несериализуемого автоматического отката».

Редактировать

Из вашего примера кода я не уверен, что вы можете установить уровень изоляции транзакции после начала. Вы должны активировать журналы запросов на MySQL и выполнить все это, а затем проверить, что другие транзакции, выполняемые CMS, все еще не находятся на уровне сериализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...