Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как выполнить несколько запросов в транзакции

Короткий ответ

Оберните запросы в beginTransaction() и commit(), а при ошибке вызовите rollBack():

<?php
 
$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance INTEGER CHECK (balance >= 0))');
$pdo->exec('INSERT INTO accounts (balance) VALUES (500), (100)');
 
function transfer(PDO $pdo, int $from, int $to, int $amount): void
{
    $pdo->beginTransaction();
 
    try {
        $pdo->prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?')->execute([$amount, $to]);
        $pdo->prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?')->execute([$amount, $from]);
        $pdo->commit();
    } catch (Throwable $e) {
        $pdo->rollBack();
 
        throw $e;
    }
}
 
transfer($pdo, 1, 2, 200);
 
try {
    transfer($pdo, 1, 2, 9999);
} catch (PDOException) {
    echo "Transfer cancelled\n";
}
 
echo implode(', ', $pdo->query('SELECT balance FROM accounts ORDER BY id')->fetchAll(PDO::FETCH_COLUMN));

Результат:

Transfer cancelled
300, 300

Что произошло

Второй перевод зачислил деньги получателю, но списание нарушило ограничение таблицы. rollBack() отменил оба запроса, и балансы остались прежними: 300 и 300.

Функции из этого ответа

  • PDO — Подключение к базе данных.
  • PDOStatement — Подготовленный запрос и его результат.
  • Throwable — Общий интерфейс всего, что можно бросить и поймать.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.