Как сформировать уникальный 16-значный числовой идентификатор в 1С и избежать появления дублей?

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

При разработке под платформу 1С иногда возникает задача создания собственного уникального идентификатора фиксированной длины — например, из 16 цифр. Стандартный УникальныйИдентификатор имеет длину 36 символов и содержит дефисы, поэтому он не всегда подходит под подобные требования. Попытки использовать обычный генератор случайных чисел часто приводят к появлению дубликатов в базе данных, даже если перед записью выполняется проверка на существование кода.

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

Почему возникают дубли при случайной генерации?

Проанализируем ситуацию, с которой сталкиваются разработчики при использовании генератора случайных чисел (объект ГенераторСлучайныхЧисел):

  1. Случайность не означает уникальность. Математически генератор случайных чисел не гарантирует отсутствие повторяющихся значений на определенной выборке. Со временем вероятность коллизии возрастает.
  2. Особенности инициализации генератора. Если создавать объект Новый ГенераторСлучайныхЧисел при каждом вызове функции без задания начального числа, платформа инициализирует его на основе системного времени. В случае вызова нескольких генераций подряд внутри одной секунды они могут выдать одинаковую последовательность.
  3. Состояние гонки (Race Condition). Если в системе работают параллельно несколько пользователей или фоновых заданий, стандартная проверка через метод НайтиПоРеквизиту или запрос к базе данных может сработать одновременно в двух сеансах. В этот момент кода еще нет в базе, оба вызова получают подтверждение, что код свободен, и записывают два одинаковых элемента.

Способ 1. Использование миллисекунд универсальной даты

Рассмотрим наименее трудоемкий способ формирования 16-значного идентификатора — использование функции ТекущаяУниверсальнаяДатаВМиллисекундах. Данное значение представляет собой монотонно растущее число, гарантирующее временную уникальность.

Посмотрим на пример функции формирования такого кода:


Функция СоздатьЧисловойГУИД(ИмяСправочника) Экспорт

    УИД = Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧЦ=16; ЧВН=; ЧГ=0");
    
    // Проверяем наличие элемента с таким кодом/реквизитом
    Если Не Справочники[ИмяСправочника].НайтиПоРеквизиту("УИД", УИД) = Справочники[ИмяСправочника].ПустаяСсылка() Тогда
        Возврат СоздатьЧисловойГУИД(ИмяСправочника);
    Иначе
        Возврат УИД;
    КонецЕсли;

КонецФункции

В данном примере функция Формат с параметром ЧГ=0 отключает группировку тысяч, а параметр ЧВН= дополняет значение нулями слева, сохраняя ровно 16 символов.

Обратите внимание: Если вызовы происходят в рамках одной миллисекунды (например, при массовой загрузке данных в цикле), миллисекунды могут совпасть. Чтобы избежать коллизий в высокой нагрузке, рекомендуется комбинировать этот метод с дополнительной проверкой или счетчиком.

Способ 2. Комбинация метки времени и генератора чисел

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

Рассмотрим схему формирования такого кода:

  1. Вычисляется число минут с начала года (в одном году содержится 525 600 минут, что занимает 6 цифр).
  2. Генерируется случайное число из 10 цифр с помощью объекта ГенераторСлучайныхЧисел.
  3. Значения объединяются в 16-значную строку.

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

Способ 3. Использование штатной нумерации или вспомогательных объектов

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

  1. Стандартный код справочника. Можно задать длину кода справочника равной 16 символам и выбрать тип кода Число. Платформа будет автоматически увеличивать значение на единицу при создании каждого нового элемента.
  2. Вспомогательный справочник-нумератор. Если код основного справочника должен быть строковым или сформированным иначе, можно создать отдельный служебный справочник с числовым кодом длины 16. При записи нового объекта создается элемент служебного справочника, его код сохраняется в реквизит основного объекта, что гарантирует абсолютную уникальность.
  3. Регистр сведений с хранением кодов. Для предотвращения повторного использования кодов даже после удаления элементов справочника создается независимый регистр сведений. При записи элемента сгенерированный идентификатор фиксируется в регистре. При удалении элемента запись из регистра не удаляется.

Как гарантировать уникальность при параллельной работе?

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

Рассмотрим правильный порядок действий при записи:

  1. Открываем транзакцию с помощью НачатьТранзакцию().
  2. Устанавливаем исключительную блокировку через объект БлокировкаДанных на ключевой ресурс или служебный регистр.
  3. Генерируем код и проверяем его наличие в базе данных.
  4. Записываем объект и фиксируем транзакцию с помощью ЗафиксироватьТранзакцию().

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

← На главную