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

Уровень изоляции READ COMMITTED

SQL SELF
40 уровень , 0 лекция
Открыта

Давайте разберёмся, что делает уровень изоляции READ COMMITTED. Его название как бы подсказывает, что все, что мы читаем в рамках транзакции, уже "закоммичено" другими транзакциями. Прямо как в жизни, когда мы верим только в те сплетни, которые официально записаны в протокол.

Если серьезно, этот уровень гарантирует, что транзакция не может увидеть изменения, которые внесены другими транзакциями, но не зафиксированы. Это решает проблему, известную как "грязное чтение" (Dirty Read). Однако, стоит помнить, что данные, которые вы читаете, могут измениться, если другая транзакция успеет сделать коммит между вашими запросами. Это создает риск возникновения "неповторяющегося чтения" (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. Он обеспечивает защиту от грязных чтений, что делает его хорошим вариантом для большинства стандартных операций. Однако в сценариях, требующих строгой консистентности, могут потребоваться более строгие уровни изоляции. Выбор уровня изоляции должен зависеть от ваших конкретных задач и требований по производительности.

2
Задача
SQL SELF, 40 уровень, 0 лекция
Недоступна
Создание транзакции с уровнем изоляции READ COMMITTED
Создание транзакции с уровнем изоляции READ COMMITTED
Комментарии (2)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Евгений Уровень 49 Expert
2 октября 2025
В лекциях ранее и в самом задании допускается грубая синтаксическая ошибка. Команду SET TRANSACTION ISOLATION LEVEL следует использовать после открытия транзакции, а не до. Во-первых, вот источник, где говорится "sets the characteristics of the current transaction", т.е. устанавливает параметры текущей транзакции. А во-вторых это подтверждается моими собственными тестами.
Sergey Mos Уровень 13
24 октября 2025
Абсолютно верное замечание. И можно вообще без SET использовать в таком виде: BEGIN TRANSACTION ISOLATION LEVEL ...