Пошук уроків, статей та іншого контенту
Розглянете транзакцію як атомарну послідовність операцій і зрозумієте, навіщо вона потрібна.
Транзакція — це атомарна послідовність операцій із базою даних.
Атомарність означає, що всі операції транзакції виконуються як одне ціле:
або успішно виконуються всі операції;
або не зберігається жодна з них.
Це важливо, коли одна дія складається з кількох змін. Наприклад, переказ грошей між двома рахунками:
зняти гроші з рахунку відправника;
додати гроші до рахунку отримувача.
Якщо виконати лише першу операцію, гроші зникнуть. Транзакція не дозволяє залишити базу даних у такому неповному стані.
У PostgreSQL для керування транзакціями використовують такі команди:
BEGIN;
-- операції транзакції
COMMIT;BEGIN — починає транзакцію;
COMMIT — підтверджує всі зміни;
ROLLBACK — скасовує всі зміни після BEGIN.
Також замість BEGIN можна написати BEGIN TRANSACTION.
Розглянемо приклад із банківськими рахунками:
-- Створюємо тимчасову таблицю для прикладу.
-- Вона буде існувати лише протягом поточного підключення.
CREATE TEMP TABLE accounts (
id integer PRIMARY KEY,
owner_name text NOT NULL,
balance numeric(12, 2) NOT NULL
);
-- Додаємо два рахунки.
INSERT INTO accounts (id, owner_name, balance)
VALUES
(1, 'Олена', 1000.00),
(2, 'Андрій', 500.00);
-- Починаємо транзакцію переказу.
BEGIN;
-- Знімаємо 200 з рахунку Олени.
UPDATE accounts
SET balance = balance - 200
WHERE id = 1;
-- Додаємо 200 на рахунок Андрія.
UPDATE accounts
SET balance = balance + 200
WHERE id = 2;
-- Підтверджуємо обидві зміни.
COMMIT;
-- Перевіряємо результат.
SELECT id, owner_name, balance
FROM accounts
ORDER BY id;Після COMMIT залишки будуть такими:
Олена — 800.00;
Андрій — 700.00.
Обидві операції належать одній транзакції й були збережені разом.
Якщо під час транзакції стало зрозуміло, що зміни не потрібно зберігати, використовується ROLLBACK.
-- Починаємо нову транзакцію.
BEGIN;
-- Тимчасово змінюємо баланс Олени.
UPDATE accounts
SET balance = balance - 100
WHERE id = 1;
-- Скасовуємо всі зміни після BEGIN.
ROLLBACK;
-- Баланс залишився таким самим, як до транзакції.
SELECT id, owner_name, balance
FROM accounts
WHERE id = 1;Після ROLLBACK віднімання 100 не зберігається.
Якщо одна з команд транзакції завершується помилкою, PostgreSQL переводить транзакцію в стан помилки. Подальші команди в цій транзакції не виконуються, доки не буде зроблено ROLLBACK.
Наприклад:
BEGIN;
UPDATE accounts
SET balance = balance - 50
WHERE id = 1;
-- Помилка: унікальний ідентифікатор 1 вже існує.
INSERT INTO accounts (id, owner_name, balance)
VALUES (1, 'Невірний запис', 0);
-- Потрібно завершити транзакцію відкатом.
ROLLBACK;У цьому прикладі скасовано не лише помилковий INSERT, а й попередній UPDATE. Баланс рахунку не зміниться.
Після ROLLBACK можна почати нову транзакцію.
Клієнти PostgreSQL часто працюють у режимі автоматичної фіксації — autocommit.
У такому режимі кожна окрема SQL-команда автоматично виконується як власна транзакція. Наприклад:
UPDATE accounts
SET balance = balance + 100
WHERE id = 2;Якщо команда успішна, її зміни одразу фіксуються. Якщо команда завершується помилкою, її зміни скасовуються.
Однак дві окремі команди в режимі autocommit не є однією спільною транзакцією. Щоб об'єднати їх, потрібно явно використати BEGIN і COMMIT.
BEGIN;
UPDATE accounts
SET balance = balance - 100
WHERE id = 1;
UPDATE accounts
SET balance = balance + 100
WHERE id = 2;
COMMIT;Транзакцію варто використовувати, коли:
одна бізнес-операція змінює кілька рядків;
потрібно змінити кілька таблиць узгоджено;
часткове виконання операції може пошкодити дані;
усі зміни мають бути збережені або всі скасовані.
Приклад із переказом коштів:
зменшити баланс рахунку A
збільшити баланс рахунку BЦі операції мають бути в одній транзакції. Якщо друга операція не може виконатися, першу потрібно скасувати.
Загальна схема транзакції виглядає так:
BEGIN;
-- Виконання пов'язаних операцій.
-- Якщо все успішно:
COMMIT;
-- Якщо виникла проблема:
-- ROLLBACK;На практиці застосунок вирішує, яку команду виконати після перевірки результатів операцій:
COMMIT, якщо всі умови виконані;
ROLLBACK, якщо сталася помилка або операцію потрібно скасувати.
Якщо зміни виконуються окремими командами без BEGIN, кожна команда може бути зафіксована незалежно.
У результаті перша операція збережеться, а друга може завершитися помилкою. Для пов'язаної послідовності потрібно явно починати транзакцію.
Якщо після BEGIN не виконати ні COMMIT, ні ROLLBACK, транзакція залишається відкритою.
Це може утримувати зміни та блокування довше, ніж потрібно. Тому транзакцію слід завершувати одним із двох способів:
COMMIT;або:
ROLLBACK;Після помилки PostgreSQL не виконує наступні команди цієї транзакції. Спочатку потрібно зробити відкат:
ROLLBACK;І лише після цього починати нову транзакцію.
Після COMMIT зміни вже збережені. Виклик ROLLBACK після цього не скасує їх, оскільки транзакція вже завершена.
Транзакція об'єднує кілька операцій в одну логічну одиницю.
Атомарність означає: або зберігаються всі зміни, або не зберігається жодна.
BEGIN починає транзакцію.
COMMIT зберігає зміни.
ROLLBACK скасовує незбережені зміни.
Пов'язані операції, наприклад переказ коштів, потрібно виконувати в межах однієї транзакції.
Після помилки транзакцію потрібно завершити через ROLLBACK.