Transactions
Транзакції
Транзакція — це послідовність операцій з базою даних, які розглядаються як єдине ціле. Іншими словами, або всі операції виконуються успішно, або, у випадку помилки, жодна з них не виконується. Транзакція ніколи не буде завершена успішно, якщо хоча б одну операцію в послідовності дій не вдалося виконати через помилку.
Розглянемо приклад. Уявимо, переказ грошей з одного банківського рахунку на інший:
- Початок транзакції: ти ініціюєш переказ грошей.
- Зняття суми: з твого рахунку знімається певна сума грошей.
- Додавання суми: ця сума грошей додається на рахунок одержувача.
- Завершення транзакції: якщо обидві операції виконані успішно, транзакція завершується.
Якщо ж виникає помилка (наприклад, недостатньо коштів на рахунку), транзакція скасовується, і ніякі зміни у фінансовому стані рахунків не відбуваються.
💡 Транзакції захищають цілісність даних та гарантують, що всі частини транзакції виконуються повністю. Це допомагає уникнути ситуацій, коли частково виконані операції можуть призвести до помилок або неконсистентності даних.
Властивості транзакцій
Кожна транзакція в базі даних повинна відповідати чотирьом основним властивостям, відомим як ACID:
-
Атомарність (Atomicity). Атомарність означає «все або нічого». У контексті транзакції, це означає, що всі операції (кроки) в транзакції мають бути виконані успішно, або, у випадку невдачі хоча б однієї з них, жодна операція не буде виконана.
Приклад: якщо ти пишеш текстове повідомлення і воно не відправляється через відсутність мережі, то повідомлення залишиться невідправленим, а не буде відправлено наполовину.
-
Консистентність (Consistency). Консистентність забезпечує, що транзакція переводить базу даних з одного коректного стану в інший коректний стан, з дотриманням усіх правил бази даних.
Приклад: якщо у тебе є правило, що баланс на банківському рахунку не може бути меншим ніж 0, то транзакція, що зменшує баланс, не буде дозволена, якщо вона призведе до балансу меншим ніж 0.
-
Ізоляція (Isolation). Ізоляція означає, що транзакції виконуються незалежно одна від одної. Зміни, зроблені однією транзакцією, не впливають на інші транзакції до того моменту, як вони будуть завершені.
Приклад: якщо двоє людей одночасно оновлюють один і той же запис у базі даних, то перший не побачить змін, внесених другим, поки його власна транзакція не завершиться.
-
Стійкість (Durability). Стійкість гарантує, що як тільки транзакція завершена, її результати залишаються у базі даних навіть у випадку системного збою, наприклад, відключення живлення.
Приклад: після того, як документ був успішно збережений, він залишиться збереженим навіть якщо комп'ютер раптово вимкнеться.
💡 ACID-властивості важливі для забезпечення цілісності даних в БД. Вони гарантують, що застосунки, які використовують бази даних, захищені від помилок, непередбачених збоїв та проблем з паралельним доступом до даних. Це особливо важливо у фінансових системах, системах управління ресурсами підприємства, та загалом всюди, де важлива цілісність даних.
Використання транзакцій у базах даних
Операції над транзакціями є досить важливими. Вони гарантують, що база даних залишається в узгодженому стані, і дозволяють легко скасувати зміни, якщо це необхідно.
Для прикладу використаємо нашу БД company та створимо в ній ще одну табличку. Уявимо, що в нашій компанії є внутрішня валюта, яку працівники можуть перераховувати один одному в подяку чи в якості подарунка. Щоб зберігати інформацію про рахунки працівників, нам знадобиться така таблиця:
CREATE TABLE BonusAccounts (
AccountID INT AUTO_INCREMENT,
EmployeeID INT,
FOREIGN KEY (EmployeeID) REFERENCES Employees(EmployeeID) ON DELETE CASCADE,
Balance INT,
PRIMARY KEY (AccountID)
);
До речі, зверни увагу на конструкцію FOREIGN KEY. Вона позначає, що поле EmployeeID містить ID працівника з таблиці employees. ON DELETE CASCADE означає, що якщо працівника видалять з таблиці employees, дані його рахунку з цієї таблиці теж будуть видалені. Замість CASCADEможуть бути також SET NULL (тоді поле з ID працівника просто стане пустим) або NO ACTION (тоді працівника не можна буде видалити з БД поки в нього є рахунок).
Тепер заведемо бонусні рахунки двом нашим працівникам. На кожному рахунку початковий баланс буде 5:
Здійснимо транзакцію та перекажемо одиницю внутрішньої валюти з рахунку працівника з ID 1 на рахунок працівника з ID 2. Щоб почати транзакцію використаємо оператор START TRANSACTION:
START TRANSACTION;
UPDATE BonusAccounts SET Balance = Balance - 1 WHERE EmployeeID = '1';
UPDATE BonusAccounts SET Balance = Balance + 1 WHERE EmployeeID = '2';
COMMIT;
Усередині транзакції виконається оновлення даних двох рахунків: в одному баланс збільшиться на 1, а в іншому — зменшиться. Далі нам потрібно зафіксувати ці зміни, щоб переконатися, що вони є постійними. Це можна зробити за допомогою COMMIT.
Перевіримо результат виконання транзакції за допомогою SELECT-запиту:
Якщо під час виконання транзакції сталася помилка і потрібно скасувати зміни, можна скористатися оператором ROLLBACK. Тоді транзакція буде «відкочена», оператори вставки та оновлення не будуть виконані, а у БД не відбудеться жодних змін:
START TRANSACTION;
UPDATE BonusAccounts SET Balance = Balance - 1 WHERE EmployeeID = '1'; UPDATE BonusAccounts SET Balance = Balance + 1 WHERE EmployeeID = '2';
SELECT * FROM company.BonusAccounts;
ROLLBACK;
SELECT * FROM company.BonusAccounts;
Як бачиш, транзакції — це дуже зручний вбудований механізм, який дозволяє доволі просто забезпечити консистентність даних.