безопасность — предотвращение двойного исполнения. PHP финансовое приложение

Если у меня есть сценарий, который уменьшает баланс пользователей в системе двойного учета, и злонамеренный пользователь решает выполнить этот сценарий на своем аккаунте на двух разных компьютерах (или на одном и том же компьютере) ровно в одно и то же время, все это будет бежать дважды, верно? Так вот мой упрощенный гипотетический сценарий.

    $balance = $user->ledger->getBalance(); // returns 5000
$amount = 3000;
if ($amount <= $balance) {
$user->ledger->decrease($amount);
}

echo $user->ledger->getBalance(); // echo's 2000

Если скрипт запускается один за другим, второе выполнение завершится неудачно, потому что в учетной записи осталось только 2000, и он попытался уменьшить его на 3000.

Если сценарии выполняются одновременно в одно и то же время, не будут ли оба баланса равны 5000, и оба выполнения сценария вычитают 3000, оставляя отрицательное значение в регистре?

Как бы вы предотвратили такое? Чрезвычайно важно поддерживать целостность данных в этой таблице базы данных.

0

Решение

Ты говоришь о условия гонки и они очень важно устранить в финансовом кодексе.

Все, что следует шаблону get / test / set, будет иметь огромные проблемы. Вы не можете сделать это.

Вместо этого возьмите шаблон set / test / fail. Попробуйте и вычтите, используя атомарный оператор SQL, такой как отдельная операция или блок транзакции. Если это приводит к отрицательному балансу, откатитесь назад.

Например, это плохой:

balance = query("SELECT balance FROM accounts WHERE account_id=?")
balance -= amount
balance = query("UPDATE accounts SET balance=?")

Все может произойти между извлечением и записью.

Вместо этого вы можете сделать это там, где этот запрос либо успешен, либо неудачен, его нельзя прервать:

query("UPDATE accounts SET balance=balance-? WHERE account_id=? AND balance>?")

Этот запрос не будет запущен, если не будет достаточно остатка. Вы получите нулевые строки, измененные в результате.

Вы также можете сделать это с помощью бухгалтерского учета в стиле двойной бухгалтерской книги, попытавшись вставить необходимые строки бухгалтерской транзакции, а затем проверить SUM() обеспечить нулевой или положительный баланс для исходного счета. Если это не так, отменить транзакцию с ROLLBACK, Изменения не применяются.

Есть много способов структурирования этих INSERT заявления, чтобы сделать невозможным для отрицательного баланса, как INSERT INTO x SELECT ... FROM y где вы можете применить условия к подзапросу для возврата нулевых строк в случае недостаточного баланса.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]