Назад к вопросам
Middle+
11
Расскажите про транзакции в базе данных и блокировки. Как бы вы обрабатывали одновременное списание и пополнение баланса?
Компании, где спрашивали
Exceed
Ответ от нейросети
sobes.tech AI
Транзакции в базе данных — это набор операций, которые выполняются как единое целое. Они обеспечивают свойства ACID:
- Атомарность — все операции либо выполняются, либо не выполняются вовсе.
- Согласованность — база данных переходит из одного корректного состояния в другое.
- Изолированность — параллельные транзакции не влияют друг на друга.
- Долговечность — после подтверждения транзакции изменения сохраняются.
Блокировки используются для обеспечения изолированности и предотвращения конфликтов при одновременном доступе.
Для обработки одновременного списания и пополнения баланса важно:
- Использовать транзакцию, чтобы операции списания и пополнения были атомарными.
- Применять блокировки на уровне строк (например,
SELECT ... FOR UPDATE), чтобы предотвратить гонки при чтении и записи баланса.
Пример на SQL:
BEGIN;
-- Блокируем строку с балансом
SELECT balance FROM accounts WHERE id = :account_id FOR UPDATE;
-- Проверяем и обновляем баланс
UPDATE accounts SET balance = balance - :amount WHERE id = :account_id;
-- Аналогично для пополнения другого счета
COMMIT;
В PHP это можно реализовать через PDO с транзакциями:
$pdo->beginTransaction();
// SELECT FOR UPDATE
$stmt = $pdo->prepare('SELECT balance FROM accounts WHERE id = ? FOR UPDATE');
$stmt->execute([$accountId]);
$balance = $stmt->fetchColumn();
if ($balance >= $amount) {
// списание
$pdo->prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?')->execute([$amount, $accountId]);
// пополнение
$pdo->prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?')->execute([$amount, $otherAccountId]);
$pdo->commit();
} else {
$pdo->rollBack();
throw new Exception('Недостаточно средств');
}
Такой подход гарантирует корректность баланса при одновременных операциях.