Почему в 1С 7.7 при записи элемента справочника возникает ошибка «при проведении транзакции произошла ошибка объект заблокирован»?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При работе в конфигурациях на платформе 1С:Предприятие 7.7, особенно при миграции на современные версии Microsoft SQL Server (например, 2008 R2), разработчики и системные администраторы могут столкнуться с парадоксальной ситуацией. При попытке сохранить новый элемент справочника в интерактивном диалоге (форме элемента) система аварийно прерывает операцию с сообщением: «при проведении транзакции произошла ошибка объект заблокирован». При этом запись нового элемента непосредственно через форму списка проходит без каких-либо ошибок, а модули формы и объекта полностью пусты и не содержат программных транзакций или блокировок.

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

В чем кроется корень проблемы: различия между формой списка и диалогом элемента

Когда мы создаем запись непосредственно в строке формы списка, платформа 1С 7.7 выполняет минимальный набор проверок и формирует простой SQL-запрос на вставку записи. Однако при сохранении элемента через диалоговое окно активизируется внутренний платформенный алгоритм контроля целостности иерархии:

  1. Рекурсивный обход дерева родителей. Платформа начинает проверять цепочку подчинения по полю PARENTID (для многоуровневых справочников) или PARENTEXT (для подчиненных справочников) вверх до корневого уровня, чтобы рассчитать глубину вложенности и проверить права доступа.
  2. Зацикливание иерархии (кольцевые ссылки). Если в результате ручных правок, сбоев оборудования или некорректно отработавших обменов данными в справочнике образовалась петля (например, группа «А» вложена в группу «Б», а группа «Б» указана родителем группы «А», либо группа ссылается сама на себя), рекурсивный алгоритм платформы зацикливается. В процессе проверки накладываются разделяемые и монопольные блокировки. Попадая на уже заблокированный в рамках этой же транзакции узел, платформа определяет конфликт и возвращает ошибку «объект заблокирован».
  3. Осиротевшие записи. Если значение поля PARENTID указывает на несуществующий в базе идентификатор (запись родителя была физически удалена или не перенеслась), системный механизм валидации контекста также падает при попытке наложить блокировку на отсутствующую запись.
  4. Эскалация блокировок (Lock Escalation) в MS SQL 2008 R2. В СУБД MS SQL Server 2008 R2 по умолчанию включен агрессивный алгоритм укрупнения блокировок. Если при проверке уникальности или сканировании иерархии СУБД решает укрупнить блокировку со строк до уровня всей таблицы (X-lock на таблицу SCxxx), любая последующая проверка в этой же транзакции приводит к взаимной блокировке. В MS SQL 2005 данный механизм вел себя мягче, поэтому на старых версиях СУБД с теми же поврежденными данными ошибка могла не проявляться.

Шаг 1: Диагностика поврежденных записей прямыми SQL-запросами

Для точного обнаружения битых строк и зацикленных групп проанализируем таблицу справочника напрямую через SQL Server Management Studio. Имя таблицы справочника в базе данных 1С 7.7 имеет формат SCxxx (узнать точный номер таблицы можно в файле метаданных 1cv7.dd или 1cv7.dds).

Выполним поиск групп, которые ссылаются сами на себя в качестве родителя:


SELECT ID, DESCR, PARENTID 
FROM SC1234 
WHERE PARENTID = ID AND ISFOLDER = 1;

Проверим наличие записей, у которых указан несуществующий родитель («осиротевшие» элементы и группы):


SELECT ID, DESCR, PARENTID 
FROM SC1234 
WHERE PARENTID <> '     0   ' 
  AND PARENTID NOT IN (SELECT ID FROM SC1234);

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

Шаг 2: Восстановление целостности базы данных

Рассмотрим способы устранения найденных нарушений в зависимости от доступности базы данных и регламентного окна на обслуживание.

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

Шаг 3: Настройка параметров блокировок в MS SQL Server 2008 R2

Если проверка целостности показала отсутствие явных петель, но транзакция по-прежнему падает из-за конфликта блокировок на уровне СУБД при работе нескольких пользователей, отключим эскалацию блокировок для конкретной таблицы справочника.

Выполним в консоли СУБД команду, запрещающую повышать уровень блокировки со строк до блокировки таблицы:

ALTER TABLE SC1234 SET (LOCK_ESCALATION = DISABLE);

Проанализируем также уровень совместимости базы данных (Compatibility Level). В среде SQL Server 2008 R2 при использовании патчей («секретных релизов») рекомендуется использовать совместимость 100 (SQL Server 2008), избегая искусственного понижения до уровня 80 (SQL Server 2000), так как старый режим совместимости на новом ядре СУБД нередко провоцирует сбои во встроенном оптимизаторе запросов.

В качестве финальной профилактической меры выполним реиндексацию таблиц и пересчет счетчиков служебной таблицы _1SSYS, чтобы исключить дублирование внутренних уникальных идентификаторов платформы.

← На главную