Sobes.tech
Back to questions
Middle+
12

Расскажите про транзакции в базе данных и блокировки. Как бы вы обрабатывали одновременное списание и пополнение баланса?

Companies where asked
Exceed

Answer from AI

sobes.tech AI

Транзакции в базе данных — это набор операций, которые выполняются как единое целое. Они обеспечивают свойства ACID:

  • Атомарность — все операции либо выполняются, либо не выполняются вовсе.
  • Согласованность — база данных переходит из одного корректного состояния в другое.
  • Изолированность — параллельные транзакции не влияют друг на друга.
  • Долговечность — после подтверждения транзакции изменения сохраняются.

Блокировки используются для обеспечения изолированности и предотвращения конфликтов при одновременном доступе.

Для обработки одновременного списания и пополнения баланса важно:

  1. Использовать транзакцию, чтобы операции списания и пополнения были атомарными.
  2. Применять блокировки на уровне строк (например, 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('Недостаточно средств');
}

Такой подход гарантирует корректность баланса при одновременных операциях.