Почему возникает конфликт управляемых блокировок при записи чека во время закрытия смены в 1С:Розница?

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

В типовых решениях «1С:Предприятие», таких как «1С:Розница», процедура закрытия кассовой смены является одной из самых ресурсоемких операций. Часто системные администраторы и программисты сталкиваются со странной ситуацией: несмотря на то, что программный код устанавливает управляемую блокировку только на конкретные документы (чеки ККМ) определенной кассы, пользователи на других кассах не могут пробить чек из-за ошибки «Конфликт блокировок при выполнении транзакции». Рассмотрим подробнее, почему зоны действия блокировок, которые теоретически не должны пересекаться, вызывают взаимные ожидания, и как с этим бороться.

Анализ механизма управляемой блокировки в коде

Проанализируем фрагмент кода, который чаще всего становится инициатором проблемы при закрытии смены. Программа пытается заблокировать все проведенные чеки, которые еще не были архивированы, по конкретной кассе:


УстановитьПривилегированныйРежим(Истина);
ЗапросПоЧекам.Текст = 
    "ВЫБРАТЬ
    | Док.Ссылка КАК Ссылка
    |ИЗ
    | Документ.ЧекККМ КАК Док
    |ГДЕ
    | Док.КассаККМ = &КассаККМ
    | И Док.Проведен
    | И НЕ Док.СтатусЧекаККМ = ЗНАЧЕНИЕ(Перечисление.СтатусыЧековККМ.Архивный)";

РезультатЗапросаПоЧекам = ЗапросПоЧекам.Выполнить();

НачатьТранзакцию();
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Документ.ЧекККМ");
ЭлементБлокировки.ИсточникДанных = РезультатЗапросаПоЧекам.Выгрузить();
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "Ссылка");
Блокировка.Заблокировать();

На первый взгляд, использование объекта БлокировкаДанных с указанием конкретных ссылок через ИспользоватьИзИсточникаДанных должно гарантировать, что будут заблокированы только те записи, которые относятся к закрываемой кассе. Однако на практике запись нового чека на совершенно другой кассе «встает в очередь» и отваливается по таймауту (обычно через 20 секунд). Выясним основные причины этого поведения.

Причина 1: Эскалация на уровне менеджера блокировок 1С

Важно понимать, что управляемые блокировки живут не в СУБД (MS SQL, PostgreSQL), а в памяти сервера приложений «1С:Предприятие». У менеджера управляемых блокировок есть свои алгоритмы оптимизации. Если количество объектов, передаваемых в ИсточникДанных, слишком велико (по разным оценкам, порог составляет от 20 000 до 100 000 записей), сервер 1С может принять решение о трансформации блокировки. Вместо того чтобы хранить в памяти тысячи отдельных ссылок, он блокирует всё пространство имен целиком — в данном случае весь тип Документ.ЧекККМ.

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

Причина 2: Конфликты на уровне регистров

Даже если мы явно блокируем только документы, процесс закрытия смены в «1С:Розница» неизбежно сопровождается записью движений в регистры накопления и сведений. Проанализируем, какие ресурсы могут быть общими для разных касс:

  1. Регистр «Товары на складах»: Если все кассы работают с одного склада, то при проведении документов (например, при формировании «Отчета о розничных продажах») система устанавливает блокировки на измерения «Номенклатура» и «Склад».
  2. Регистр «Продажи»: Интенсивная запись в этот регистр при обработке сотен чеков может вызвать блокировку итогов.
  3. Регистр «Денежные средства ККМ»: Хотя здесь есть измерение «КассаККМ», при определенных настройках СУБД может блокировать страницы данных, содержащие записи по разным кассам.

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

Причина 3: Нехватка ресурсов и блокировки СУБД

Разберем ситуацию, когда ошибка выглядит как TTIMEOUT, но причина кроется в аппаратной части. Когда выполняется транзакция закрытия смены, сервер СУБД испытывает колоссальную нагрузку на дисковую подсистему и процессор. В этот момент:

Как диагностировать проблему с помощью Технологического Журнала?

Чтобы не гадать, а точно знать причину, нам необходимо настроить сбор данных Технологического Журнала (ТЖ). Нас интересуют два события: TTIMEOUT (само событие ошибки) и TLOCK (установка блокировок). Рассмотрим пример настройки logcfg.xml:


<config xmlns="http://v8.1c.ru/7.4/config/logcfg">
  <log location="C:\Logs\Locks" history="24">
    <event>
      <eq property="Name" value="TTIMEOUT"/>
    </event>
    <event>
      <eq property="Name" value="TLOCK"/>
    </event>
    <property name="all"/>
  </log>
</config>

При анализе логов обратим внимание на следующие параметры:

Рекомендации по решению проблемы

Выяснив причину, мы можем применить один из следующих подходов для минимизации конфликтов:

1. Оптимизация порций данных

Вместо того чтобы блокировать и обрабатывать все чеки за смену одной транзакцией, попробуем реализовать порционную обработку. Разберем логику: обрабатываем по 100-200 чеков, фиксируем транзакцию и делаем небольшую паузу. Это позволит другим кассам «проскочить» со своими короткими транзакциями записи чека в промежутках между нашими блоками.

2. Индексация и обслуживание СУБД

Убедимся, что все поля, участвующие в отборах (особенно КассаККМ и СтатусЧекаККМ), проиндексированы. Также проанализируем фрагментацию индексов и актуальность статистики в MS SQL. Высокая фрагментация часто приводит к тому, что СУБД выбирает неоптимальный план запроса с избыточными блокировками.

3. Использование разделения итогов

Если конфликт происходит на уровне регистров накопления, проверим, включен ли режим Разделение итогов для этих регистров. Этот механизм позволяет разным сеансам одновременно писать данные в регистр, создавая отдельные записи в таблице итогов, которые позже объединяются фоновым заданием.

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

← На главную