При переходе к разработке на платформе 1С 8.3 программисты часто сталкиваются с путаницей в терминологии: уровни изоляции транзакций, блокировки СУБД и управляемые блокировки 1С. Кажется, что это одно и то же, но на самом деле это разные уровни одной системы обеспечения целостности данных. Разберем подробно, как эти механизмы взаимодействуют друг с другом, зачем они нужны и как влияют на производительность системы.
Для начала выясним причину разделения этих понятий. Уровень изоляции — это свойство транзакции, которое определяет, насколько изменения, внесенные одной транзакцией, видны другим параллельным транзакциям. Это своего рода «правила игры», которые устанавливает СУБД (MSSQL, PostgreSQL и др.).
Блокировки — это конкретный инструмент, с помощью которого СУБД или сама платформа 1С реализует эти правила. Проанализируем простую аналогию: уровень изоляции — это закон, запрещающий заходить в комнату, пока там идет совещание, а блокировка — это физический замок на двери.
В 1С 8.3 при использовании режима «Управляемые блокировки» (который является стандартом для современных конфигураций) происходит разделение обязанностей:
Рассмотрим подробнее режим, в котором работает MSSQL под управлением 1С 8.3. По умолчанию для баз с управляемыми блокировками включается параметр READ_COMMITTED_SNAPSHOT. Это версионный уровень изоляции. Разберем по шагам, что происходит в СУБД:
Когда одна транзакция изменяет строку, SQL-сервер не заменяет данные «на месте». Он копирует старую версию строки в специальное хранилище в базе tempdb. Если в это же время другая транзакция хочет прочитать эту строку, она не ждет окончания первой транзакции. Она просто идет в tempdb и считывает последнюю зафиксированную (committed) версию данных.
Что это дает? Читатели больше не блокируют писателей, а писатели не блокируют читателей. Это колоссально повышает параллельность работы системы. Однако у этого режима есть особенность: блокировка на запись снимается сразу после выполнения команды UPDATE или INSERT (если это не противоречит логике транзакции), а блокировки на чтение (S-блокировки) практически не накладываются.
Проанализируем ситуацию: если СУБД в режиме RCSI позволяет всем свободно читать данные, то как гарантировать, что остаток товара на складе не станет отрицательным? Если два пользователя одновременно прочитают остаток «10 шт.» и оба попытаются списать «6 шт.», СУБД позволит им обоим прочитать «10», так как данные еще не изменены. В итоге мы получим «-2» на складе.
Именно здесь вступают в дело управляемые блокировки. Мы должны явно в коде перед чтением остатков «поставить забор»:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ОстаткиНоменклатуры");
ЭлементБлокировки.УстановитьЗначение("Номенклатура", ВыбранныйТовар);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
Этот код выполняется на стороне сервера 1С до того, как запрос уйдет в СУБД. Если другой сеанс уже установил такую же блокировку, второй сеанс будет ждать на уровне менеджера блокировок 1С, даже не пытаясь мучить SQL-сервер запросами.
Выясним, какие именно блокировки накладывает MSSQL, когда запрос все-таки доходит до него. Основные типы:
tempdb), ни менять.deadlock (взаимоблокировок).Важным нюансом являются блокировки намерений (Intent Locks: IS, IX, SIX). Рассмотрим их назначение. Представьте, что вы хотите заблокировать всю таблицу. Чтобы СУБД не пришлось проверять каждую из миллиона строк на наличие мелких S или X блокировок, она при наложении блокировки на строку помечает всю таблицу флагом «намерения» (IX или IS). Теперь другой процесс, глядя на заголовок таблицы, сразу видит, что внутри кто-то работает.
Иногда система ведет себя непредсказуемо. Рассмотрим механизм эскалации (Lock Escalation). Если ваш запрос (например, тяжелый отчет или групповая обработка) пытается заблокировать более 5000 строк в одной таблице, MSSQL решает сэкономить память и заменяет тысячи мелких блокировок строк на одну огромную блокировку всей таблицы.
В этот момент управляемые блокировки 1С могут показывать полную свободу, но пользователи не смогут записать ни один документ, связанный с этой таблицей, так как СУБД физически закрыла доступ к объекту. Это одна из главных причин «зависаний» при проведении больших партий документов.
Посмотрим на отличия от старого (автоматического) режима 1С 8.2. В нем использовался уровень изоляции Repeatable Read или Serializable. В этом режиме SQL-сервер удерживал S-блокировки на всех прочитанных данных до самого конца транзакции.
Проанализируем пример: вы прочитали цены номенклатуры просто для справки в начале длинной транзакции. В автоматическом режиме вся таблица цен (или ее значительная часть) будет заблокирована на чтение до конца транзакции, и никто не сможет обновить цены. В управляемом режиме 1С 8.3 (RCSI) чтение цен не создаст никаких препятствий для других пользователей, так как S-блокировки не удерживаются.
Выясним важный момент для тех, кто использует PostgreSQL. В отличие от MSSQL, где переход в автоматический режим просто повышает уровень изоляции, 1С на PostgreSQL в автоматическом режиме ведет себя крайне агрессивно. Для имитации Serializable платформа может наложить команду LOCK TABLE, которая полностью блокирует параллельную работу. Поэтому для PostgreSQL использование управляемых блокировок является фактически единственным способом обеспечить многопользовательскую работу.
tempdb в MSSQL, а также наличие эскалаций блокировок до уровня таблиц.Таким образом, эффективная работа в 1С 8.3 строится на синергии: СУБД обеспечивает высокую скорость и параллельность доступа, а программист через управляемые блокировки гарантирует корректность бизнес-данных в критических узлах системы.