Ответ
Транзакция — это группа SQL-запросов, которая выполняется как единая, атомарная операция. Она следует принципам ACID. Если все запросы выполняются успешно, изменения фиксируются (commit). Если возникает ошибка на любом этапе, все уже выполненные в рамках этой транзакции изменения откатываются (rollback), оставляя базу данных в согласованном состоянии.
Практический пример с PDO (перевод средств между счетами):
$pdo = new PDO('mysql:host=localhost;dbname=bank', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
// Начало транзакции
$pdo->beginTransaction();
// Списываем сумму со счета отправителя
$stmt1 = $pdo->prepare("UPDATE accounts SET balance = balance - :amount WHERE id = :from_id");
$stmt1->execute([':amount' => 100, ':from_id' => 1]);
// Зачисляем сумму на счет получателя
$stmt2 = $pdo->prepare("UPDATE accounts SET balance = balance + :amount WHERE id = :to_id");
$stmt2->execute([':amount' => 100, ':to_id' => 2]);
// Фиксируем изменения, если все прошло успешно
$pdo->commit();
echo "Transfer successful";
} catch (PDOException $e) {
// В случае любой ошибки откатываем все изменения
$pdo->rollBack();
echo "Transfer failed: " . $e->getMessage();
}
Ключевые моменты для PHP-разработчика:
- Изоляция через
beginTransaction(): Запросы внутри транзакции изолированы от других соединений до моментаcommit()(уровень изоляции зависит от настройки СУБД). - Обязательная обработка ошибок: Транзакции требуют использования
try...catchдля гарантированного вызоваrollBack()при исключении. - Поддержка драйверов: Транзакции работают с PDO для всех поддерживающих их СУБД (MySQL/InnoDB, PostgreSQL) и с расширением mysqli.
- Вложенные транзакции: PDO может эмулировать вложенные транзакции через
SAVEPOINT, но реальная вложенность поддерживается на уровне самой СУБД (например, в PostgreSQL).
Ответ 18+ 🔞
А, слушай, про транзакции? Ну это ж, бля, основа основ, как не упасть в глубокую жопу при работе с деньгами или любыми другими важными данными. Представь себе: ты переводишь сто рублей с одного счёта на другой. Если просто выполнить два запроса подряд, может случиться пиздец. Первый запрос прошёл — деньги списались, а второй — наебнулся с ошибкой. И всё, сотня испарилась в никуда, клиент охуеет, а тебе потом искать, куда она подевалась, доверия ебать ноль.
Вот именно для этого и придумали транзакции. Это такая атомарная операция, ёпта. Либо всё выполняется успешно, либо нихуя не меняется. Как будто ты либо перенёс стакан, не пролив ни капли, либо даже не притронулся к нему. Всё держится на четырёх китах — принципах ACID, но если по-простому: операция надёжная, как швейцарские часы, и изолированная от другого говна, которое в это же время лезет в базу.
Смотри, как это выглядит в коде на PDO, на примере того самого перевода. Главное — обернуть всё в try...catch, иначе будет тебе хиросима.
$pdo = new PDO('mysql:host=localhost;dbname=bank', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
// Начало транзакции
$pdo->beginTransaction();
// Списываем сумму со счета отправителя
$stmt1 = $pdo->prepare("UPDATE accounts SET balance = balance - :amount WHERE id = :from_id");
$stmt1->execute([':amount' => 100, ':from_id' => 1]);
// Зачисляем сумму на счет получателя
$stmt2 = $pdo->prepare("UPDATE accounts SET balance = balance + :amount WHERE id = :to_id");
$stmt2->execute([':amount' => 100, ':to_id' => 2]);
// Фиксируем изменения, если все прошло успешно
$pdo->commit();
echo "Transfer successful";
} catch (PDOException $e) {
// В случае любой ошибки откатываем все изменения
$pdo->rollBack();
echo "Transfer failed: " . $e->getMessage();
}
Видишь, в чём соль? Сначала говоришь базе: «Так, бля, внимание, начинаем» — это beginTransaction(). Потом выполняешь свои манипуляции. Если на любом этапе, хоть на первом, хоть на втором запросе, вылезет ошибка — выполнение прыгнет в catch. И там команда rollBack() отменит ВСЁ, что уже успело выполниться в этой транзакции. Деньги волшебным образом вернутся на исходный счёт, как будто нихуя и не было. Если же всё прошло гладко, как по маслу — делаешь commit(), и изменения окончательно вбиваются в базу. Красота, да?
Теперь ключевые моменты, чтобы не быть распиздяем:
- Изоляция. Когда ты начал транзакцию, другие запросы могут не видеть твои «промежуточные» изменения, пока ты не сделал коммит. Это спасает от гонок и прочего мудацкого поведения. Уровень этой изоляции можно настраивать, но это уже тонкости.
- Обработка ошибок — ОБЯЗАТЕЛЬНА. Без
try...catchты рискуешь оставить транзакцию висящей в воздухе, а это, считай, овердохуища проблем. База будет держать блокировки, и всё начнёт тормозить и падать. Всегда лови исключения и делай откат. - Драйверы. PDO — молодец, он умеет работать с транзакциями для нормальных движков баз, типа InnoDB в MySQL или PostgreSQL. С тем же MyISAM это, конечно, не прокатит, там транзакций нет от слова совсем.
- Вложенность. Тут интересно. PDO может прикинуться умным и сэмулировать вложенные транзакции через
SAVEPOINT, если драйвер не поддерживает. Но по-настоящему это работает, например, в PostgreSQL. В общем, смотри по документации, чтобы не получить хуй в пальто вместо ожидаемого поведения.
Короче, запомни: любые операции, где важен целостный результат из нескольких шагов — переводы, оформление заказов, обновление связанных данных — это прям святая святых для транзакций. Без них — чих-пых тебя в сраку и потерянные данные.