Ось урок, створений спеціально для вас у стилі David Malan. Уявіть, що ви сидите в аудиторії Сандерс Театру в Гарварді (або перед монітором з чашкою кави), а ми починаємо занурення в одну з найважливіших тем баз даних.
🎓 Урок: Транзакції та ACID. Або "Все або нічого"
Привіт усім! Радий вас бачити. 👋
Сьогодні ми поговоримо про річ, яка відділяє "просто зберігання даних" від надійних, професійних систем, яким довіряють мільярди доларів. Ми говоримо про Транзакції.
1. 🔥 Вступ: Кошмар банкіра
Уявіть ситуацію. Ви відкриваєте банківський додаток, щоб переказати 1000 гривень своєму другові. Ви натискаєте "Надіслати". Гроші списуються з вашого рахунку... і в цей момент в серверній банку вимикається світло. ⚡️ Темрява.
Сервер перезавантажується. Ви дивитесь на свій баланс: грошей немає (-1000 грн). Дзвоните другу: "Прийшли?" Друг каже: "Ні, нічого немає".
Питання: Де ваші гроші? Вони зникли у цифровому небутті?
Якби бази даних працювали просто як текстові файли, це траплялося б постійно. Але ми не можемо цього дозволити. Нам потрібен механізм, який гарантує: або дія відбувається повністю, або не відбувається зовсім. Жодних "наполовину".
Ось тут на сцену виходять Транзакції.
Аналогія: Уявіть, що ви купуєте каву за готівку. Транзакція — це момент обміну. Ви простягаєте купюру, бариста простягає каву. Ви не відпустите купюру, доки не схопите стаканчик. Якщо бариста впустить каву — ви заберете гроші назад. Це єдиний неподільний процес.
2. 🧠 Теоретична база: Що таке ACID?
Транзакція — це послідовність операцій (одна або більше), які база даних сприймає як єдине ціле.
Але щоб транзакція була надійною, вона має відповідати чотирьом золотим правилам. Ми називаємо їх акронімом ACID. Запам'ятайте це слово, воно буде з вами все життя.
Розберемо його "під капотом", але простою мовою:
⚛️ A — Atomicity (Атомарність)
Пам'ятаєте фізику? Атом (колись вважали) неподільним. Так і тут. Транзакція неподільна. * Як це працює: Якщо в транзакції 10 кроків, і на 10-му стається помилка — база даних скасовує (roll back) усі попередні 9 кроків. Все повертається до стану, як було на початку. * Головне: "Все або нічого".
✅ C — Consistency (Узгодженість)
Транзакція переводить базу даних з одного правильного стану в інший правильний стан. * Як це працює: База перевіряє правила (constraints). Наприклад, якщо у вас є правило "Баланс не може бути меншим за 0", і транзакція намагається це порушити — база скаже "СТОП" і скасує транзакцію. * Головне: Закон є закон.
🛡 I — Isolation (Ізольованість)
Уявіть, що тисяча людей одночасно купують квитки на поїзд. * Як це працює: Транзакції не повинні заважати одна одній. Якщо я змінюю рядок у таблиці, ви не повинні бачити мої "чернетки", доки я не закінчу. Ви побачите або старий стан, або вже новий. * Головне: Ніякого підглядання за незавершеною роботою.
💾 D — Durability (Довговічність/Надійність)
Якщо база даних сказала "ОК, збережено" — це назавжди. * Як це працює: Навіть якщо через мілісекунду після підтвердження сервер згорить, метеорит впаде на дата-центр або вимкнуть живлення — дані записані на жорсткий диск (в лог транзакцій) і відновляться при запуску. * Головне: Написане пером не вирубаєш сокирою.
3. 🧪 Приклади: Від хаосу до порядку
Давайте подивимось на це в коді (використовуємо SQL, наприклад, PostgreSQL або MySQL).
Сценарій: Переказ грошей (Alice -> Bob)
У нас є таблиця accounts:
| id | name | balance |
|----|-------|---------|
| 1 | Alice | 1000 |
| 2 | Bob | 500 |
Приклад 1: Без транзакції (Небезпечно! 💀)
-- Крок 1: Забираємо в Еліс
UPDATE accounts SET balance = balance - 100 WHERE name = 'Alice';
-- 💥 ОЙ! ТУТ ВИМКНУЛИ СВІТЛО АБО СТАЛАСЯ ПОМИЛКА SQL! 💥
-- Крок 2: Цей рядок ніколи не виконається
UPDATE accounts SET balance = balance + 100 WHERE name = 'Bob';
Результат: У Еліс 900, у Боба 500. 100 монет зникли. Система зламана.
Приклад 2: Використовуємо Транзакцію (Безпечно 🛡)
Як ми це виправляємо? Ми "огортаємо" наші команди в блок транзакції.
BEGIN; -- Почати транзакцію (ми відкриваємо дужку)
-- Крок 1
UPDATE accounts SET balance = balance - 100 WHERE name = 'Alice';
-- Крок 2
UPDATE accounts SET balance = balance + 100 WHERE name = 'Bob';
COMMIT; -- Зафіксувати зміни (закриваємо дужку і зберігаємо)
Що тут відбулося?
Поки ми не написали COMMIT, зміни існують лише у "чернетці". Інші користувачі їх ще не бачать. Якщо світло вимкнеться до команди COMMIT, база даних при запуску побачить, що транзакція не завершена, і автоматично все скасує. Гроші Еліс повернуться.
Приклад 3: Ручний відкат (Rollback)
Іноді ми самі хочемо скасувати зміни, якщо зрозуміли, що щось пішло не так.
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE name = 'Alice';
-- Уявіть, що тут ми (або наш код) перевірили баланс і зрозуміли, що сталася помилка
-- Наприклад, ми помилково намагаємося надіслати гроші неіснуючому користувачу.
ROLLBACK; -- Скасувати все! Повернутися в минуле!
Результат: База даних "забуває" все, що було після BEGIN. У Еліс знову 1000.
4. 🛠 Практична частина
А тепер ваша черга! Відкрийте термінал або SQL-редактор.
Завдання 1: Класика
Створіть таблицю wallets (id, user, money). Додайте туди 'Max' (1000) і 'Alex' (1000). Напишіть транзакцію, де Max переказує 200 Alex-у. Перевірте фінальний результат.
Завдання 2: "Ой, передумав"
Почніть транзакцію (BEGIN). Видаліть всі гроші у Max (UPDATE... SET money = 0). Перевірте SELECT-ом (ви побачите 0). Тепер напишіть ROLLBACK. Перевірте знову. Чи повернулися гроші? (Магія, правда?)
Завдання 3: Інтернет-магазин (Міні-кейс)
У вас є таблиця products (id, name, stock_quantity) і orders (id, product_id, amount).
Напишіть транзакцію для покупки товару:
1. Зменшити stock_quantity на 1.
2. Створити запис в orders.
Питання: Чому ці дві дії обов'язково мають бути в одній транзакції?
Завдання 4: Питання "А що, якщо..."
Що станеться, якщо в Завданні 3 ви спробуєте купити товар, якого на складі 0, а у вас стоїть Constraint (обмеження) CHECK (stock_quantity >= 0)?
Спробуйте це зробити всередині транзакції. Чи створиться запис в orders, якщо UPDATE викличе помилку бази даних?
5. 💡 Мислення як у розробника
Ви тепер знаєте синтаксис, але як думають профі?
-
Помилка новачка: Робити транзакції занадто довгими.
- Уявіть: Ви відкрили транзакцію (
BEGIN), змінили важливий рядок... і пішли пити каву, не зробившиCOMMIT. - Наслідок: Вся база даних може "зависнути" для інших користувачів, бо ви заблокували цей рядок.
- Правило: Транзакції мають бути максимально швидкими. Відкрили -> Змінили -> Закрили.
- Уявіть: Ви відкрили транзакцію (
-
Де обробляти логіку?
- Зазвичай ви керуєте транзакціями з коду програми (Python, Java, PHP).
- Структура завжди така:
python try: db.begin_transaction() # ... купа запитів ... db.commit() # Якщо все ок except Error: db.rollback() # Якщо хоч одна помилка — скасовуємо все print("Щось пішло не так, зміни скасовано")
-
Не використовуйте транзакції для всього.
- Якщо ви робите один простий
SELECT, транзакція вам, швидше за все, не потрібна (сучасні БД самі про це дбають). Транзакції потрібні там, де є зміна кількох пов'язаних даних.
- Якщо ви робите один простий
6. 🧩 Підсумок
Отже, що ми сьогодні винесли?
- Транзакція — це капсула часу. Або все відбувається, або нічого.
- ACID — це ваша гарантія спокійного сну (Атомарність, Узгодженість, Ізоляція, Довговічність).
- COMMIT зберігає зміни, ROLLBACK рятує від помилок.
Тепер ви можете будувати системи, де гроші не зникають у повітрі, а склади не продають товари, яких не існує. Ви вмієте захищати цілісність даних!
🔜 Тизер наступного уроку: Ми говорили, що транзакції ізольовані. Але наскільки? Що, як один користувач читає дані, поки інший їх змінює? На наступному уроці ми заглянемо у безодню Рівнів Ізоляції (Isolation Levels) і дізнаємося, що таке "Брудне читання" (Dirty Read) і "Фантоми". Звучить як назва трилера, чи не так?
А на сьогодні це все. This was Transactions and ACID.