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

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

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

Как устроен механизм автонумерации в платформе 1С

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

Проанализируем ключевые особенности работы этого механизма:

  1. Кэширование диапазонов в ОЗУ: Кластер резервирует диапазон свободных номеров в оперативной памяти и выдает их новым объектам по порядку. Значение счетчика сбрасывается и перечитывается из базы только при исчерпании пула или принудительной команде обновления.
  2. Транзакционные откаты: Если сеанс запросил номер из пула, но транзакция записи завершилась ошибкой или была отменена, полученный номер «сгорает». Это исключает дублирование, но создает пропуски («дыры») в нумерации.
  3. Сбитый формат и ручной ввод: Если в базу вручную или внешней обработкой был записан объект с кодом нестандартной длины, лишним пробелом или измененным префиксом, платформа принимает эту строку за максимальный номер. В результате счетчик перестает корректно инкрементировать числовую составляющую.

Главная причина: подключение двух независимых кластеров к одной базе данных

Наиболее опасной архитектурной ошибкой является ситуация, когда два независимых кластера серверов 1С (например, основной сервер и сервер для обменов/фоновых задач) настроены на работу с одной и той же информационной базой в SQL Server. В этом случае каждый кластер выделяет свой собственный независимый пул номеров в ОЗУ и ничего не знает о действиях соседнего менеджера. Рано или поздно оба кластера пытаются выдать один и тот же код разным объектам, что приводит к гарантированному сбою уникальности.

Помимо нарушения нумерации, одновременная работа нескольких кластеров с единой СУБД несет критические риски разрушения данных:

  1. Сбой управляемых блокировок: Пространство управляемых блокировок хранится в памяти сервиса блокировок конкретного кластера. Разные кластеры не синхронизируют блокировки между собой, из-за чего возможна параллельная несогласованная перезапись одних и тех же данных.
  2. Нарушение оперативной отметки времени: Генерация меток для последовательностей документов и партионного учета теряет глобальную упорядоченность.
  3. Дублирование регламентных заданий: Одно и то же расписание заданий начинает параллельно выполняться на двух серверах.
  4. Повреждение служебных сервисов: Рассинхронизируются индексы полнотекстового поиска и нарушается целостность журнала регистрации.

Решение 1. Объединение серверов в единый кластер (Основное решение)

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

Разберем по шагам, как распределить нагрузку внутри единого кластера:

  1. Подключим второй рабочий сервер в состав существующего кластера через консоль администрирования 1С:Предприятия.
  2. Настроим Требования назначения функциональности. Если требовалось разгрузить основной сервер от обменов и фоновых задач, создадим правило, привязывающее сервис фоновых заданий к выделенному рабочему серверу.
  3. Убедимся, что к базе данных в SQL Server обращается только один кластер.

Решение 2. Программное обновление нумерации объектов

Если серверная архитектура настроена верно, но автонумератор сбился из-за некорректно введенного вручную номера или сбоя транзакции, используем платформенный метод ОбновитьНумерациюОбъектов(). Этот метод принудительно очищает кэш в памяти сервера и заново вычисляет максимальный номер непосредственно из таблиц базы данных.

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


// Обновление нумерации для конкретного справочника
ОбновитьНумерациюОбъектов(Метаданные.Справочники.Номенклатура);

// Обновление нумерации для конкретного документа
ОбновитьНумерациюОбъектов(Метаданные.Документы.РеализацияТоваровУслуг);

// Обновление нумерации для массива объектов метаданных
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(Метаданные.Справочники.Контрагенты);
МассивОбъектов.Добавить(Метаданные.Справочники.ДоговорыКонтрагентов);
ОбновитьНумерациюОбъектов(МассивОбъектов);

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

Решение 3. Явная инициализация кода при программном создании

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

Рассмотрим пример правильной установки номера с префиксом:


НовыйЭлемент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйЭлемент.Наименование = "Новый партнер";

// Явно устанавливаем код с учетом префикса информационной базы или узла
НовыйЭлемент.УстановитьНовыйКод("УТ");

Попытка
    НовыйЭлемент.Записать();
Исключение
    // В случае возникновения коллизии обновляем кэш и повторяем генерацию
    ОбновитьНумерациюОбъектов(Метаданные.Справочники.Контрагенты);
    НовыйЭлемент.УстановитьНовыйКод("УТ");
    НовыйЭлемент.Записать();
КонецПопытки;

Рекомендации по интеграции

Если для интеграции используется COM-соединение (comcntr), следует учитывать его зависимость от разрядности библиотек и операционной системы. Для повышения стабильности обменов рекомендуется переходить на современные интеграционные механизмы платформы: HTTP-сервисы, Web-сервисы (SOAP) или стандартный интерфейс OData, работающие по протоколу HTTP/HTTPS через веб-сервер.

← На главную