JavaRush /Курси /SQL SELF /Рівень ізоляції READ COMMITTED

Рівень ізоляції READ COMMITTED

SQL SELF
Рівень 40 , Лекція 0
Відкрита

Давай розберемось, що робить рівень ізоляції READ COMMITTED. Його назва як би натякає, що все, що ми читаємо в рамках транзакції, вже "закомічено" іншими транзакціями. Прямо як у житті, коли ми віримо тільки тим чуткам, які офіційно записані в протоколі.

Якщо серйозно, цей рівень гарантує, що транзакція не може побачити зміни, які внесені іншими транзакціями, але ще не зафіксовані. Це вирішує проблему, відому як "брудне читання" (Dirty Read). Але треба пам’ятати, що дані, які ти читаєш, можуть змінитися, якщо інша транзакція встигне зробити commit між твоїми запитами. Це створює ризик виникнення "неповторюваного читання" (Non-Repeatable Read).

У PostgreSQL рівень ізоляції READ COMMITTED встановлений за замовчуванням. Це як дефолтний режим — тобі не треба нічого спеціально налаштовувати, щоб ним користуватись.

Приклад використання рівня ізоляції READ COMMITTED

Давай подивимось, як це працює на практиці. Уявімо, що у нас є таблиця accounts, яка містить інформацію про користувачів і їх баланси:

CREATE TABLE accounts (
    account_id SERIAL PRIMARY KEY,
    account_name TEXT NOT NULL,
    balance NUMERIC(10, 2) NOT NULL
);

INSERT INTO accounts (account_name, balance)
VALUES ('Alice', 1000.00), ('Bob', 500.00);

Тепер уявімо наступну ситуацію. Сесія 1 і Сесія 2 — два герої нашої історії, обидва працюють з таблицею accounts. Ось що відбувається:

Сесія 1:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_name = 'Alice';
-- Ніякого COMMIT або ROLLBACK поки що.

У цей момент з balance Аліси тимчасово віднято 100 одиниць, але результат ще не зафіксований.

Сесія 2:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

BEGIN;
SELECT balance FROM accounts WHERE account_name = 'Alice';

Результат: Сесія 2 бачить баланс Аліси як 1000.00, бо транзакція Сесії 1 ще не завершена (COMMIT не виконаний). Рівень READ COMMITTED захищає нас від "брудного читання".

Сесія 1 завершує транзакцію:

COMMIT;

Тепер баланс Аліси оновлений, і в базі даних зафіксовано значення 900.00.

Сесія 2 повторює запит:

SELECT balance FROM accounts WHERE account_name = 'Alice';

Результат: тепер Сесія 2 бачить оновлений баланс Аліси — 900.00. Зверни увагу, що результат відрізняється від попереднього запиту, який повертав 1000.00. Це проблема "неповторюваного читання".

Коли використовувати READ COMMITTED?

Рівень ізоляції READ COMMITTED — це баланс між продуктивністю і консистентністю. Але є кілька сценаріїв, де він підходить просто ідеально:

  1. Прості CRUD-операції: коли ти просто читаєш або оновлюєш дані без складних взаємозв’язків.

  2. Оновлення записів: наприклад, масове оновлення даних у таблиці, де важливо одразу бачити зафіксовані зміни.

  3. Обробка транзакцій: платіжні системи, які дозволяють користувачам бачити тільки підтверджені дані.

Але якщо ти виконуєш складні аналітичні запити або працюєш з великими обсягами даних, можливо, варто розглянути інший рівень ізоляції, наприклад, REPEATABLE READ.

Переваги і недоліки рівня ізоляції READ COMMITTED

Рівень ізоляції READ COMMITTED — це щось типу золотої середини. Він захищає тебе від брудних даних: ти не побачиш зміни, які інша транзакція почала, але ще не закінчила. Тобто ніхто не прочитає «сиру» інформацію, яка може бути тут же відкочена.

Цей режим працює швидше, ніж більш строгі рівні (REPEATABLE READ або SERIALIZABLE), бо не вимагає складних блокувань і додаткових перевірок. Він досить легкий і, водночас, надійний — саме тому використовується за замовчуванням і чудово підходить для більшості повсякденних задач.

Хоча він запобігає брудному читанню, READ COMMITTED не захищає від:

  • "Неповторюваного читання" (Non-Repeatable Read): значення даних може змінитися, якщо інша транзакція внесе зміни між запитами.
  • "Фантомного читання" (Phantom Read): інша транзакція може додати рядки, які вплинуть на результат твого запиту.

Поради при роботі з READ COMMITTED

Завжди завершуй транзакції: не забувай використовувати COMMIT або ROLLBACK, інакше можуть виникнути проблеми з блокуваннями.

Переконайся, що рівень ізоляції достатній: якщо тобі треба гарантувати, що дані не зміняться під час виконання транзакції, розглянь REPEATABLE READ.

Використовуй індексацію: це допоможе PostgreSQL швидше знаходити дані і застосовувати зміни.

Приклад: обробка замовлень

Припустимо, у нас є таблиця orders, в якій зберігаються дані про замовлення:

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    customer_name TEXT NOT NULL,
    status TEXT NOT NULL DEFAULT 'pending'
);

INSERT INTO orders (customer_name, status)
VALUES ('Alice', 'pending'), ('Bob', 'pending');

Ми хочемо оновити статус замовлень, які знаходяться у стані "pending":

BEGIN;
SELECT * FROM orders WHERE status = 'pending';
UPDATE orders SET status = 'completed' WHERE status = 'pending';
COMMIT;

Якщо під час виконання інша транзакція додасть нове замовлення зі статусом "pending" і зробить COMMIT, наша транзакція не врахує цей рядок, бо він був доданий після початку читання.

Це приклад "фантомного читання". Якщо ти хочеш уникнути таких ситуацій, треба використовувати SERIALIZABLE.

Рівень ізоляції READ COMMITTED — це вибір за замовчуванням для більшості баз даних, включаючи PostgreSQL. Він забезпечує захист від брудних читань, що робить його класним варіантом для більшості стандартних операцій. Але в сценаріях, де потрібна жорстка консистентність, можуть знадобитися більш строгі рівні ізоляції. Вибір рівня ізоляції має залежати від твоїх конкретних задач і вимог до продуктивності.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ