В процессе работы многопользовательских систем на платформе 1С:Предприятие 8.3 одной из наиболее острых проблем является возникновение ошибки "Конфликт блокировок при выполнении транзакции". Эта ситуация возникает, когда несколько сеансов одновременно пытаются получить доступ к одним и тем же данным в режиме записи или при избыточном чтении в транзакции. В рамках данной статьи мы подробно разберем, как перейти на механизм управляемых блокировок, как правильно использовать объект БлокировкаДанных и как минимизировать время нахождения системы в состоянии ожидания.
Прежде всего, проанализируем ситуацию, почему возникают блокировки. В старых версиях платформы или при использовании автоматического режима блокировок, СУБД (MS SQL Server, PostgreSQL) самостоятельно блокировала целые таблицы или значительные диапазоны страниц при выполнении любого запроса внутри транзакции. Это приводило к тому, что второй пользователь не мог записать документ, пока первый просто формировал отчет.
Современный подход подразумевает использование управляемого режима. В этом случае ответственность за то, какие данные будут заблокированы, ложится на плечи разработчика. Рассмотрим подробнее, как это работает на практике. Управляемая блокировка устанавливается не на уровне таблиц базы данных, а на уровне логических пространств имен внутри кластера 1С.
Для начала работы нам необходимо убедиться, что свойство конфигурации "Режим управления блокировкой данных" установлено в значение Управляемый. Это критически важный момент. Если оставить значение Автоматический, то система продолжит использовать избыточные блокировки СУБД, игнорируя ваши программные установки.
Разберем по шагам, что происходит при смене режима:
Для программной установки блокировки в 1С используется объект БлокировкаДанных. Давайте рассмотрим пример кода, который необходимо вставить перед выполнением запроса, считывающего остатки для последующего списания. Это классический сценарий, где без блокировки возможна ситуация "отрицательных остатков".
Проанализируем пример кода:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементБлокировки.УстановитьЗначение("Склад", СкладСсылка);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.ИсточникДанных = СписокТоваров;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
Блокировка.Заблокировать();
В данном фрагменте мы выполняем следующие действия:
БлокировкаДанных.Исключительный. Это значит, что никто другой не сможет ни прочитать (с целью блокировки), ни записать эти данные до конца нашей транзакции.ИсточникДанных. Если в документе много позиций, не нужно вызывать метод УстановитьЗначение в цикле. Достаточно передать таблицу значений или результат запроса, и платформа сама заблокирует нужные комбинации измерений.Выясним причину, почему даже при использовании управляемых блокировок могут возникать Deadlocks (взаимные блокировки). Часто это происходит из-за разного порядка обращения к ресурсам. Например, один процесс блокирует сначала "Склад А", затем "Склад Б", а другой — наоборот.
Рассмотрим правила, которые помогут избежать подобных ситуаций:
Номенклатура.Запрос.Выполнить(), если результат этого запроса будет использоваться для принятия решения о записи.Если пользователи продолжают жаловаться на ошибки, нам необходимо проанализировать ситуацию с помощью технологического журнала. В настройках ТЖ следует включить события TLOCK (управляемые блокировки) и TTIMEOUT (время ожидания).
Посмотрим на пример настройки файла logcfg.xml для отслеживания проблем:
<config xmlns="http://v8.1c.ru/7.4/config">
<log location="C:\Logs\1C_Locks" history="24">
<event>
<eq property="Name" value="TLOCK"/>
</event>
<event>
<eq property="Name" value="TTIMEOUT"/>
</event>
<property name="all"/>
</log>
</config>
После сбора логов мы сможем увидеть конкретную строку кода, которая вызвала блокировку, и понять, какой другой сеанс удерживал ресурс слишком долго. Особое внимание стоит уделить свойству WaitConnections — оно покажет номер сеанса-виновника.
Важно помнить, что для регистров сведений блокировка устанавливается по набору всех измерений. Если вы не укажете значение какого-либо измерения, будет заблокирован весь диапазон, что может привести к снижению производительности. Для регистров бухгалтерии ситуация еще сложнее: блокировка по счету может затрагивать смежные итоги.
Рассмотрим рекомендации по работе с регистрами:
Записать(Истина) (с замещением) платформа автоматически устанавливает управляемую блокировку по регистратору.НаборЗаписей, старайтесь всегда устанавливать Отбор по всем измерениям перед записью.ДЛЯ ИЗМЕНЕНИЯ в языке запросов только тогда, когда это действительно необходимо, так как это эквивалентно установке исключительной блокировки на считываемые записи.Подводя итог, отметим, что переход на управляемые блокировки — это не просто смена флажка в свойствах конфигурации, а изменение культуры разработки. Разберем основные тезисы:
БлокировкаДанных должен стать вашим основным инструментом при проведении документов и записи важных данных.Deadlock.Соблюдение этих правил позволит вашей системе масштабироваться до сотен и тысяч одновременно работающих пользователей без существенных задержек и ошибок блокировок.