При параллельной работе пользователей в многопользовательской системе неизбежно возникает конкуренция за общие данные. В платформе 1С:Предприятие в управляемом режиме блокировок за согласованность отвечает менеджер транзакционных блокировок кластера серверов. Выясним причину появления термина несовместимые блокировки, разберем базовые принципы их работы и посмотрим, как избегать конфликтов и таймаутов при разработке.
Блокировка — это способ защитить данные от несогласованных изменений параллельными транзакциями. В платформе 1С управляемые блокировки объявляются не на уровне физических страниц или строк СУБД, а на логическом уровне бизнес-сущностей (областей данных конфигурации).
Блокировки двух различных транзакций считаются несовместимыми только тогда, когда одновременно выполняются два условия:
Если транзакции несовместимы, вторая транзакция ставится в очередь ожидания. Если первая транзакция не успевает зафиксироваться или откатиться до истечения времени ожидания (таймаута, по умолчанию 20 секунд), платформа генерирует исключение о превышении времени ожидания блокировки.
В управляемом режиме 1С используются два основных режима установки транзакционных блокировок через свойство РежимБлокировкиДанных:
РежимБлокировкиДанных.Разделяемый. Используется для чтения данных, которые не должны быть изменены другими транзакциями до завершения текущей. Несколько сеансов могут одновременно удерживать разделяемую блокировку на одну и ту же область.РежимБлокировкиДанных.Исключительный. Используется для записи или подготовки к изменению данных. Только одна транзакция может удерживать исключительную блокировку на конкретный ресурс.Проанализируем матрицу совместимости двух параллельных транзакций:
Рассмотрим подробнее понятие пространства блокировки. Пространство определяется именем таблицы метаданных (например, РегистрНакопления.ОстаткиНоменклатуры) и значениями полей или измерений этой таблицы.
Менеджер блокировок платформы анализирует заданные условия:
Посмотрим на пример: первая транзакция блокирует остатки по всей номенклатуре для Склад = Склад1 (поле Номенклатура не указано). Вторая транзакция пытается установить блокировку на Склад = Склад1 и Номенклатура = Товар1. Поскольку первая транзакция захватила весь склад целиком, их пространства пересекаются, и вторая транзакция переходит в состояние ожидания.
Разберем по шагам, как программно задать управляемую блокировку с максимальной точностью, чтобы минимизировать риски несовместимости с параллельными потоками:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
// Указываем источник данных, содержащий точечный список складов и номенклатуры
ЭлементБлокировки.ИсточникДанных = ТаблицаТоваров;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Склад", "Склад");
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
// Устанавливаем блокировку внутри транзакции
Блокировка.Заблокировать();
В этом примере блокируются строго те строки регистра, которые содержатся в ТаблицаТоваров, не затрагивая другие позиции номенклатуры и другие склады.
Проанализируем распространенные сценарии, приводящие к несовместимым блокировкам и взаимоблокировкам (Deadlock), а также методы их решения:
БлокировкаДанных все ключевые измерения, происходит захват избыточных данных. Всегда заполняйте все измерения регистра, по которым выполняется контроль.ЗафиксироватьТранзакцию() или ОтменитьТранзакцию(). Снять ее раньше программно невозможно. Выносите тяжелые расчеты, заполнение интерфейсных структур и выборки данных, не требующие блокировки, за пределы явных транзакций.ИспользоватьРазделениеИтогов. Это позволяет транзакциям параллельно записывать движения, избегая очередей на агрегатные таблицы итогов.УдалятьДвиженияАвтоматически, платформа в самом начале транзакции проведения накладывает исключительные блокировки на таблицы регистров для очистки старых движений, что увеличивает время удержания несовместимых блокировок. Предпочтительнее использовать управляемое удаление движений.Для детального расследования ситуаций, когда сеансы блокируют друг друга, настроим сбор событий Технологического журнала:
Regions) и режим (Locks).WaitConnections).