Как правильно понимать уровень изоляции READ COMMITTED в 1С и почему в ИТС могут быть неточности?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При изучении механизмов блокировок в 1С разработчики часто сталкиваются с разделом документации на ИТС, посвященным уровню изоляции READ COMMITTED. Описание этого уровня нередко вызывает вопросы, особенно в части утверждений о «решении проблемы неповторяемого чтения» и возможности чтения данных «не дожидаясь окончания транзакции». Разберем подробно, как работает этот механизм в современных СУБД, где документация может вводить в заблуждение и как 1С дополняет возможности СУБД собственным менеджером блокировок.

Основы уровня изоляции READ COMMITTED

Для начала вспомним классическое определение: уровень изоляции READ COMMITTED (чтение зафиксированных данных) гарантирует, что транзакция может прочитать только те данные, изменения по которым уже были зафиксированы (выполнен COMMIT). Это базовый уровень для большинства современных СУБД, таких как MS SQL Server и PostgreSQL. Его основная задача — предотвращение «грязного чтения» (Dirty Read).

Грязное чтение — это ситуация, когда одна транзакция читает данные, которые были изменены другой транзакцией, но еще не зафиксированы. Если вторая транзакция выполнит ROLLBACK (откат), первая транзакция окажется в ситуации, когда она обработала данные, которых на самом деле не существует.

Рассмотрим подробнее формулировку из ИТС: «Если моя транзакция начала изменять данные, то конкурирующая транзакция не может не только изменить, но даже прочитать их до завершения моих изменений». Здесь кроется первая ловушка. В классической блокировочной модели (Pessimistic Concurrency) пишущая транзакция накладывает эксклюзивную блокировку (X-lock), которая действительно запрещает чтение другим транзакциям, работающим на уровне READ COMMITTED. Однако в современных реалиях 1С всё немного иначе.

Версионность против блокировок (RCSI)

Проанализируем ситуацию с точки зрения современных версий платформы 1С 8.3. Начиная с версии 8.3.3, при использовании MS SQL Server 1С по умолчанию включает режим Read Committed Snapshot Isolation (RCSI). В этом режиме поведение СУБД меняется кардинально:

  1. Пишущая транзакция при изменении данных не блокирует читающие транзакции.
  2. Читающая транзакция не ждет завершения пишущей транзакции. Вместо этого она обращается к TempDB, где хранится старая версия данных, актуальная на момент начала выполнения запроса SELECT.

Именно поэтому фраза в ИТС «могут читать данные, не дожидаясь окончания моей транзакции в целом» технически верна для версионных СУБД (PostgreSQL) или MS SQL с включенным RCSI. Читающая транзакция видит «закоммиченное» состояние на момент своего старта, игнорируя текущие незавершенные изменения.

Проблема неповторяемого чтения

Выясним причину споров вокруг фразы ИТС: «Таким образом решается проблема неповторяемого чтения». В академической теории баз данных это утверждение считается ошибочным. Уровень READ COMMITTED по определению не защищает от неповторяемого чтения.

Неповторяемое чтение (Non-repeatable read) — это ситуация, когда внутри одной транзакции вы дважды выполняете один и тот же запрос на чтение, но получаете разные результаты, потому что между этими запросами другая транзакция изменила данные и зафиксировала их (COMMIT).

Разберем это на примере:

  1. Транзакция №1 читает остаток товара (результат: 10 шт).
  2. Транзакция №2 изменяет остаток на 5 шт и делает COMMIT.
  3. Транзакция №1 снова читает остаток (результат: 5 шт).

В рамках Транзакции №1 данные изменились «под ногами», что и называется неповторяемым чтением. Уровень READ COMMITTED это допускает, так как Транзакция №2 уже зафиксирована.

Почему же в ИТС написано, что проблема решается? Вероятно, авторы имели в виду, что платформа 1С в режиме управляемых блокировок перекладывает ответственность за целостность данных на плечи разработчика и Менеджер управляемых блокировок.

Роль управляемых блокировок 1С

Поскольку сама СУБД на уровне READ COMMITTED позволяет данным меняться в процессе нашей транзакции, платформа 1С использует механизм управляемых блокировок. Рассмотрим, как правильно реализовать контроль остатков, чтобы избежать проблем.

Проанализируем классический код проведения документа:


// Создаем объект блокировки
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ОстаткиНоменклатуры");
ЭлементБлокировки.УстановитьЗначение("Номенклатура", ВыбНоменклатура);
// Устанавливаем исключительную блокировку
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();

// Теперь выполняем запрос к остаткам
Запрос = Новый Запрос("ВЫБРАТЬ КоличествоОстаток ИЗ РегистрНакопления.ОстаткиНоменклатуры.Остатки(...)");
// ... проверка и запись движений

Что здесь происходит:

Таким образом, именно связка READ COMMITTED в СУБД + Исключительная управляемая блокировка в 1С фактически эмулирует уровень изоляции REPEATABLE READ или даже SERIALIZABLE для конкретных данных, решая проблему неповторяемого чтения.

Освобождение блокировок СУБД

Если же мы работаем в старой конфигурации без управляемых блокировок (автоматический режим), то MS SQL использует классические S-блокировки (Shared). Посмотрим на важный нюанс: на уровне READ COMMITTED СУБД снимает разделяемую блокировку сразу после того, как данные прочитаны, не дожидаясь завершения транзакции.

Это подтверждает тезис из обсуждения: «данные, блокируемые читающей транзакцией, освобождаются сразу после завершения операции SELECT». Это сделано для повышения параллельности, но именно это и делает неповторяемое чтение возможным в «чистой» СУБД без дополнительных механизмов 1С.

Итоги и рекомендации

Подводя итог анализу уровня изоляции READ COMMITTED, можно сделать следующие выводы:

  1. В официальной документации ИТС есть неточность: сам по себе уровень READ COMMITTED не решает проблему неповторяемого чтения. Это подтверждается как теорией БД, так и другими методическими материалами фирмы 1С (например, книгой «Профессиональная разработка в системе 1С:Предприятие»).
  2. Фраза про «не дожидаясь окончания транзакции» описывает поведение версионных СУБД или кратковременный характер S-блокировок в блокировочных СУБД.
  3. Для программиста 1С крайне важно понимать: при использовании управляемого режима уровень изоляции СУБД гарантирует только то, что вы не прочитаете «мусор» (незафиксированные изменения). Для обеспечения бизнес-логики (например, неизменности остатков в ходе проведения) обязательно использование объекта БлокировкаДанных с режимом Исключительный.
  4. Уровень READ COMMITTED является оптимальным балансом между скоростью (параллельностью) и целостностью, если разработчик грамотно использует управляемые блокировки.

Помните, что безопасность ваших данных в транзакции при уровне READ COMMITTED — это не свойство СУБД, а результат вашей работы с менеджером управляемых блокировок 1С.

← На главную