При разработке под платформу 1С иногда возникает задача создания собственного уникального идентификатора фиксированной длины — например, из 16 цифр. Стандартный УникальныйИдентификатор имеет длину 36 символов и содержит дефисы, поэтому он не всегда подходит под подобные требования. Попытки использовать обычный генератор случайных чисел часто приводят к появлению дубликатов в базе данных, даже если перед записью выполняется проверка на существование кода.
В этой статье разберем по шагам, почему генератор случайных чисел дает коллизии, выясним причину появления дублей при проверках и рассмотрим проверенные способы формирования уникального 16-значного числа.
Проанализируем ситуацию, с которой сталкиваются разработчики при использовании генератора случайных чисел (объект ГенераторСлучайныхЧисел):
Новый ГенераторСлучайныхЧисел при каждом вызове функции без задания начального числа, платформа инициализирует его на основе системного времени. В случае вызова нескольких генераций подряд внутри одной секунды они могут выдать одинаковую последовательность.НайтиПоРеквизиту или запрос к базе данных может сработать одновременно в двух сеансах. В этот момент кода еще нет в базе, оба вызова получают подтверждение, что код свободен, и записывают два одинаковых элемента.Рассмотрим наименее трудоемкий способ формирования 16-значного идентификатора — использование функции ТекущаяУниверсальнаяДатаВМиллисекундах. Данное значение представляет собой монотонно растущее число, гарантирующее временную уникальность.
Посмотрим на пример функции формирования такого кода:
Функция СоздатьЧисловойГУИД(ИмяСправочника) Экспорт
УИД = Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧЦ=16; ЧВН=; ЧГ=0");
// Проверяем наличие элемента с таким кодом/реквизитом
Если Не Справочники[ИмяСправочника].НайтиПоРеквизиту("УИД", УИД) = Справочники[ИмяСправочника].ПустаяСсылка() Тогда
Возврат СоздатьЧисловойГУИД(ИмяСправочника);
Иначе
Возврат УИД;
КонецЕсли;
КонецФункции
В данном примере функция Формат с параметром ЧГ=0 отключает группировку тысяч, а параметр ЧВН= дополняет значение нулями слева, сохраняя ровно 16 символов.
Обратите внимание: Если вызовы происходят в рамках одной миллисекунды (например, при массовой загрузке данных в цикле), миллисекунды могут совпасть. Чтобы избежать коллизий в высокой нагрузке, рекомендуется комбинировать этот метод с дополнительной проверкой или счетчиком.
Если требуется, чтобы код выглядел случайно и не был упорядочен по дате, разберем подход с объединением временного смещения и случайной составляющей. Например, можно взять количество минут или секунд с определенной фиксированной точки (начала года) и прибавить к ним случайный хвост.
Рассмотрим схему формирования такого кода:
ГенераторСлучайныхЧисел.Даже если генератор случайных чисел выдаст повторяющийся хвост, временная составляющая обеспечит уникальность итоговой строки в разные моменты времени.
Выясним причину, почему не всегда стоит писать собственные генераторы. В платформе 1С штатные механизмы нумерации уже содержат встроенную защиту от дублирования.
Число. Платформа будет автоматически увеличивать значение на единицу при создании каждого нового элемента.Чтобы окончательно исключить появление дублей при одновременной работе нескольких пользователей, любой алгоритм проверки и записи должен быть защищен механизмом управляемых блокировок.
Рассмотрим правильный порядок действий при записи:
НачатьТранзакцию().БлокировкаДанных на ключевой ресурс или служебный регистр.ЗафиксироватьТранзакцию().Использование транзакционных блокировок исключит ситуацию, когда два параллельных сеанса одновременно считают код свободным и создадут дубликаты.