На нашем курсе мы будем рассматривать транзакции трижды. И каждый раз будем открывать для себя что-то новое. Сейчас мы изучим основы транзакций. Ну а во второй половине курса разберёмся с уровнями изоляции транзакций, а в самом конце — нюансы работы вложенных транзакций.
Что такое транзакция
Начнём с простого — определения. Транзакция — это группа действий, которые выполняются только вместе. Все.
Из этого следует важный вывод: если при выполнении какого-то (любого!) действия группы произошел сбой, то откатить нужно результат работы всех остальных действий и вернуть систему в первоначальное состояние.
С точки зрения SQL, транзакция — это набор действий (например, вставка, обновление или удаление данных), которая гарантирует, что либо все операции внутри транзакции успешно завершатся, либо ни одна из них не будет выполнена. Это поведение делает работу с базами данных надёжной и согласованной, особенно в критических сценариях, таких как обработка платежей или обновление связанных данных.
Вот представьте, что вы переводите деньги между двумя банковскими счетами. Если упростить, у нас есть две последовательные операции:
- С одного счета списывается сумма.
- На другой счёт зачисляется та же сумма.
Если произойдёт сбой в самом конце операции (например, упадёт сервер), важно, чтобы ни один из пользователей не оказался в проигрыше. Другими словами, либо оба шага успешны (транзакция фиксируется), либо оба шага откатываются (транзакция отменяется).
Транзакции и принципы ACID
Транзакции основаны на принципах ACID, который напоминает нам о четырёх ключевых характеристиках:
- Atomicity (Атомарность): всё или ничего. Либо все операции внутри транзакции выполняются, либо откатываются.
- Consistency (Согласованность): данные остаются в корректном состоянии до и после транзакции.
- Isolation (Изоляция): каждая транзакция работает, как будто она единственная в системе.
- Durability (Долговечность): после фиксации данные сохраняются, даже если сервер упадёт.
Основные команды для управления транзакциями
Теперь готовьтесь к практике! Вот три главных команды для управления транзакциями:
BEGIN
Начинает новую транзакцию. Все последующие операции будут выполняться в её рамках.COMMIT
Фиксирует изменения. После выполнения этой команды все действия становятся постоянными.ROLLBACK
Отменяет изменения. Если что-то пошло не так, можно откатить транзакцию, и данные останутся в исходном состоянии.
Базовый синтаксис транзакций
Простая структура транзакции:
BEGIN;
-- здесь идут ваши SQL-операции
COMMIT;
Пример использования ROLLBACK:
BEGIN;
-- иземенение таблицы students
UPDATE students
SET grade = grade + 10
WHERE id = 1;
-- О! Мы осознали, что это была ошибка.
ROLLBACK;
Пример использования транзакции в реальной задаче
Предположим, у нас есть таблицы:
students:
| id | name | grade |
|---|---|---|
| 1 | Otto Lin | 85 |
| 2 | Anna Song | 90 |
courses:
| course_id | course_name |
|---|---|
| 1 | Математика |
| 2 | История |
Допустим, мы хотим одновременно записать студента на курс и обновить его средний балл:
BEGIN;
-- Шаг 1: Добавляем запись в таблицу "записи на курсы"
INSERT INTO course_enrollments (student_id, course_id)
VALUES (1, 2);
-- Шаг 2: Обновляем средний балл студента
UPDATE students
SET grade = grade + 5
WHERE id = 1;
COMMIT;
Что произойдёт, если упадёт сервер между первым и вторым шагом? Если бы мы не использовали транзакцию, данные оказались бы в неконсистентном состоянии: запись на курс добавится, но средний балл не обновится. Однако с транзакцией обе операции свершаются либо обе отменяются.
Работа с ошибками внутри транзакций
Иногда что-то идёт не так, и нам нужно грамотно обработать ошибку. В PostgreSQL транзакция автоматически откатится, если произойдёт ошибка.
Давацте ошибёмся специально и посмотрим, что будет. Представьте, что у нас есть ограничение на уникальность столбца student_id в таблице course_enrollments. Давайте мы попробуем добавить дублирующую строку:
BEGIN;
INSERT INTO course_enrollments (student_id, course_id)
VALUES (1, 2);
-- ОКОНЧАНИЕ ТРАНЗАКЦИИ (пока не выполнено)
COMMIT;
Если вставить студента, который уже записан на курс, произойдёт ошибка, и PostgreSQL автоматически завершит транзакцию с откатом.
Использование ROLLBACK для ручного отката
Зачастую ошибки нельзя предугадать, и вы захотите откатить транзакцию в случае, если что-то пойдёт не так:
BEGIN;
-- Добавляем нового студента
INSERT INTO students (name, grade)
VALUES ('Omori Sanny', 75);
-- Оп! Мы осознали, что студента добавили нечаянно.
ROLLBACK;
После команды ROLLBACK таблица остается неизменной — Omori Sanny так и не появился в students.
Полезные советы и типичные ошибки
Работа с транзакциями становится проще, если помнить несколько важных правил:
- Всегда используйте транзакции, если ваша операция включает более одного шага, особенно при модификации данных в нескольких таблицах.
- Никогда не забывайте фиксировать изменения (
COMMIT). Иначе транзакция останется незавершённой, а данные не изменятся. - Оборачивайте сложные операции в транзакции для сохранения согласованности данных.
- Если вы видите ошибку на любом этапе, не бойтесь использовать
ROLLBACK.
Теперь, когда вы знаете, как контролировать операции с помощью транзакций, самое время применить эти знания на практике и перейти к изучению транзакций для обеспечения целостности данных!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ