1 с конфликт блокировок

26.09.2019 18:31:38 была зафиксирована ошибка при проведении чека ККМ под пользователем АлборовПР. Это можно посмотреть в журнале регистрации:

В это время собирался полный техжурнал (не рекомендовано делать это на постоянной основе, за 1 час он достиг 5 Гб).

В техжурнале мы можем найти эту ошибку:

Временная отметка: 31:37.735009 (18 часов, 31 минута, 37 секунда, 735 миллисекунда).

Если подняться по техжурнале выше – мы видим откаты транзакций, а еще выше – их причина:

Конфликт блокировок при выполнении транзакции:

Microsoft SQL Server Native Client 11.0: Превышено время ожидания запроса на блокировку.

При попытке записи в таблицу _InfoRg25730

Это таблица марок внутреннего учета, по которой документ ЧекККМ хочет внести записи (скорее всего проставить отметку выбытия в марке).

Причиной может быть то, что в это время кто-то паралельно записывает данные в этот регистр, к примеру, по техжурналу это может быть установка статуса «Отгружен” ордерам из журнала документов продаж:

Обработка.ЖурналДокументовПродажи.Форма.КОформлениюНакладных.Форма : 2044 : ОрдерОбъект.Записать(РежимЗаписиДокумента.Проведение);

Документ.РасходныйОрдерНаТовары.МодульОбъекта : 174 : ПроведениеСерверУТ.ЗаписатьНаборыЗаписей(ЭтотОбъект);

ОбщийМодуль.ПроведениеСерверУТ.Модуль : 321 : Объект.Движения.Записать();’

Платформа Заказчика — 1С 8.3, и, теоретически, управляемые блокировки и режим изоляции snapshot должны решать проблему параллельной записи, но тут у нас блокировка СКОРЕЕ ВСЕГО из за эскалации блокировки до уровня таблицы на сервере SQL. SQL делает это автоматически, при записи в таблицу более 4000 строк в рамках одной транзакции. И, действительно, профайлер показал такие эскалации:

Самым простым выходом может стать установка флагов трассировки на SQL, запрещающей эскалацию, согласно рекомендациям 1С:

Добрый день!
Задача:
Есть две сущности — Событие и Бронь.
Событие (Справочник) это запись о том, когда клиент приходит в заведение
Бронь (Документ) это данные о том, что под событие забронированы места (например, пять дорожек боулинга).
На одно событие может не быть броней вообще (клиент просто заказал себе столик с едой для ДР) или быть несколько броней (боулинг, бильярд). Соответственно, связь по полю владелец (событие — владелец брони)
Проведения документа (функций «проведение» И «отмена проведения нет) не происходит, поскольку с базой работают довольно «простые» люди и учить их что такое проведение долго, проще сделать так, что документ всегда проведен, когда есть, и не проведен только если помечен на удаление. То есть, обработка проведения запускается при любой записи документа, при этом если пометка удаления истина, то регистры очищаются и ничего не пишется.

При записи брони нужно проверить, что места для бронирования доступны, и занять их в регистрах сведений (регистр сведений говорит, доступно ли место на дату Х, каждая бронь одного места создает две записи в регистр, недоступно с начала брони и доступно с конца брони). Это делается в ПередЗаписью модуля объекта документа Бронь.
При пометке на удаление события логично предложить также пометить на удаление все брони и наоборот, при снятии пометки — снять пометку с броней. Это делается в ПередЗаписью модуля объекта справочника Событие, после того, как проверено, что событие будет успешно записано, при этом сменится пометка удаления.
Но при этом может быть ситуация, что сначла пометили на удаление событие и его брони, затем места забронировали другой бронью, затем снимаем пометку удаления с события — со снятием её с броней — при этом движения по брони не могут быть записаны потому, что места этой брони уже заняты.
Такая бронь по моей идее останется без изменений, ибо ей будет установлено отказ=истина в ПередЗаписью.
То есть например, под событие две брони, боулинг и бильярд, для бильярда столы всё ещё свободны а боулинг дорожки уже заняты, пометка удаления должна сняться с бильярда а на боулинге остаться.
НО! 1С тут тупит.
Вот код:
Код ( (Unknown Language)):
если ЗначениеЗаполнено(Документы.Бронь.НайтиПоРеквизиту(«Событие» ,ссылка)) тогда
Режим = РежимДиалогаВопрос.ДаНет;
Ответ = Вопрос(«Снята пометка удаления. Снять пометку на удаление также с Броней, оформленных на это событие?», Режим, 0);
Если Ответ = КодВозвратаДиалога.Нет Тогда
Возврат;
КонецЕсли;
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить(«Событие», Ссылка);
Выборка=Документы.Бронь.Выбрать(,,ПараметрыОтбора);
пока Выборка.Следующий() цикл
докоб=Выборка.ПолучитьОбъект();
докоб.ПометкаУдаления=Ложь;
попытка
докоб.Записать();
исключение
КонецПопытки;
КонецЦикла;
КонецЕсли;
Идея простая — выбираем все доки по событию и ставим им пометку удаления
Но при этом докоб.Записать() вызывает ОШИБКУ если отказ=истина внутри ПередЗаписью!
Окей, я сделал попытку-исключение, но теперь Выборка.ПолучитьОбъект(); вызывает ошибку «в этой транзакции уже были ошибки!»
Да какого хрена, что они были, что с того?
Почитал интернет, говорят происходит неявная транзкция, то есть её НИКАК не остановить, не отменить и не начать заново! Офигенно.
То есть нет НИКАКОГО способа реализовать то, что я хочу (чтобы те документы, которые в своём теле получат отказ, не записались — остались помеченными — а те, которые в своём теле не получат отказ, снялись с удаления), просто потому, что кто-то в 1С решил, что нужно убивать возможность делать получение объекта при установке отказ=истина? Мне нужно дублировать код проверки легальности записи брони (места не заняты) ещё и в событии чтобы не доходило до отказа, чтоли?
Или я что-то упускаю, и есть вариант обойти эту гадость и сделать таки то, что мне нужно, без дупликации кода?

В многопользовательских системах важную роль играет правильная организация структуры и настройка блокировок. Если ее нет, пользователям придется часто сталкиваться с ошибками, вызванными конкуренцией за определенные ресурсы системы. Но существует проблема конфликта блокировок, знакомая многим пользователям. Почему возникает конфликт блокировок 1С и как его устранить?

Конфликт блокировок в 1С 8.3 и его значение

Для большинства пользователей сообщение о конфликте блокировок 1С означает лишь ошибку, мешающую им выполнять свою работу. Они хотят поскорее избавиться от этой проблемы и осаждают IT-отдел жалобами на то, что «1С не работает».

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

Рис.1 Конфликт блокировок

Причины возникновения ошибок блокировки в 1С

Показательные нагрузочные тестирования демонстрируют, что сервер 1С выдерживает параллельную работу более чем пяти тысяч пользователей. Но идеальные условия подобных экспериментов недостижимы в повседневных условиях крупных и средних компаний. Чтобы добиться аналогичного быстродействия и безошибочности, конфигурация должна быть идеально разработана и заточена под конкретные бизнес-процессы предприятия.

Если не брать идеальные варианты, то конфликты блокировок 1С встречаются по следующим причинам:

Одновременная работа пользователей с большим объемом данных. Эта первопричина продиктована внутренними механизмами 1С. Они предполагают запрет изменения данных, вовлеченных в транзакцию, запущенную от имени другого пользователя;

Ошибки и недочеты в конфигурации. В структуре типовых решений от компании «1С» учтены рекомендации по максимизации производительности. Но сторонние разработчики не всегда придерживаются высоких стандартов, и в их коде часто можно встретить следующие недочеты:

  • Неоптимальные запросы;
  • Запрос остатков в начале действий;
  • Непонимание предназначения объектов конфигурации и их неправильное применение;
  • Избыточность заложенных в системе или дополнительно разработанных блокировок.

Как исправить конфликт блокировок в 1С 8.3

Системное сообщение «конфликт блокировки при выполнении транзакции 1С 8.3» не характеризует конфигурацию в качестве неверно спроектированной. Но если подобные сигналы игнорировать, то существует вероятность в самый ответственный момент, например, при сдаче квартальной или годовой отчетности получить большие проблемы. В лучшем случае – тормозящую систему и недовольных пользователей. В худшем – неправильные данные на выходе, что может повлечь за собой штрафные санкции от контролирующих органов.

Решением проблемы конфликта блокировок в 1С 8.3 может стать перевод конфигурации на управляемый (ручной) режим управления блокировками. Реализованный в версии 8.1, механизм в руках грамотных специалистов решает проблему конфликта блокировок при транзакции в 1С.

Рис.2 Перевод на ручной режим управления блокировками

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

Быстрое решение конфликта блокировок 1С

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

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

  • Найти и завершить сеанс, заблокировавший необходимые данные. В небольших компаниях, где количество пользователей 1С не превышает пары десятков человек, это оптимальный вариант решения;
  • Если вы контролируете систему, в которой работают сотни сотрудников, поиск нужного сеанса без специализированного программного обеспечения может затянуться надолго. В этом случае намного эффективнее будет перезагрузить сервер.

Эти решения радикальные и направлены только на быстрое решение проблемы и освобождение данных для срочной сдачи отчетов. Искоренить ее можно только разобравшись в причине, из-за которой возник конфликт блокировок при выполнении транзакции 1С. После таких действий необходимо найти уязвимые места в системе, оптимизировать конфигурацию или работу сотрудников. Использовать подобные меры на постоянной основе при регулярных конфликтах блокировок на транзакциях не рекомендуется.

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

Конфигурация 1С:Предприятия 8 может работать в одном из трех режимов управления блокировками в транзакции:

  • автоматический;
  • управляемый — стандартный режим для новых конфигураций;
  • автоматический и управляемый.

В автоматическом режиме управления блокировками данных используются уровни изоляции транзакций repeatable read и serializable, обеспечиваемые системой управления базами данных. Эти уровни изоляции транзакций обеспечивают согласованное и целостное чтение данных, и от разработчика не требуется каких-либо дополнительных действий по управлению блокировками.

Управляемый режим позволяет повысить параллельность работы пользователей в клиент-серверном варианте работы за счет использования более низкого уровня изоляции транзакций базы данных (Read Committed). При записи данных в транзакции объекты встроенного языка автоматически блокируют необходимые данные. Разработчику требуется управлять блокировками данных в тех случаях, когда бизнес-логика требует согласованного и целостного чтения данных в транзакции.

Автоматический и управляемый режим позволяет использовать возможность управления блокировками в транзакции только для некоторых объектов конфигурации. Этот режим может использоваться для оптимизации параллельности работы пользователей с отдельными прикладными объектами (например, с несколькими наиболее интенсивно используемыми документами) или для постепенного перевода больших конфигураций в режим управления блокировками в транзакции.

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

Наиболее часто необходимость в управлении блокировками данных в транзакции возникает в процессе проведения документов, когда нужно прочитать, а затем записать измененные данные в те же самые таблицы. Например, если выполняется контроль остатков при проведении документа.

Специально для этого у наборов записей регистров накопления и регистров бухгалтерии существует свойство БлокироватьДляИзменения.

Если нужно контролировать остатки, а затем записывать движения в этот же регистр, то это свойство нужно установить для набора записей этого регистра в свойстве Движения.

Действие этого свойства аналогично тому, как если бы разработчик самостоятельно установил (прописал в коде) нужные управляемые блокировки 1С:Предприятия 8. Необходимую управляемую блокировку платформа установит автоматически при записи этого набора записей. В результате другие управляемые транзакции, использующие аналогичную блокировку, не смогут начать читать этот регистр, пока не закончится текущая транзакция.

Ниже приведен пример «ручного» управления блокировками данных при чтении данных регистра накопления УчетНоменклатуры в обработке проведения документа РасходнаяНакладная. В этом примере управляемые блокировки создаются и устанавливаются полностью только средствами встроенного языка.