Формирование уникального артикула

1. l4h 31.01.25 16:45 Сейчас в теме
Добрый день, коллеги.
Написал алгоритм формирования уникального артикула, в целом работает исправно , за исключением параллельных вызовов(когда два и более клиента вызывают метод одновременно, то всем вернется один и тот артикул), каким образом с такими проблемами справляются в 1с?
Алгоритм простой: запросом выбираем Артикул из таблицы номенклатура, плюсуем к нему 1 и записываем. Вызов метода "НовыйАртикул()" происходит в обработчике "ПриУстановкеНовогоКода".
По теме из базы знаний
Найденные решения
16. l4h 03.02.25 00:03 Сейчас в теме
Все, задачу решил.
Если кому-то еще надо будет, то вот:
//Функция общего модуля которая делает запрос и выбирает максимальный из существующих
Функция МаксимальныйНомерАртикула(Префикс,Характеристика = Ложь) Экспорт

    Попытка
        БлокировкаДанных = Новый БлокировкаДанных;
        БлокировкаКонстанты = БлокировкаДанных.Добавить("Константа.УА_Артикул");
        БлокировкаДанных.Заблокировать();
    Исключение                              
        //Сообщить("Объект уже заблокирован");
        Возврат Ложь;
    КонецПопытки;
//
// тут код получения нужных данных и их возврата
//
КонецФункции


//Код в объекта где требуется получить уникальный номер
Процедура УстановитьАртикул() 
    НачатьТранзакцию(); //Использование транзакций обязательно для использования блокировки объекта
    Артикул = Ложь;
    Пока  НЕ Число(Артикул) Цикл //Артикул возвращается строкой, а строка не может быть преобразована к 
                                                             //булево, поэтому преобразуем к числу, а число легко преобразуется к       
                                                             //булево, нулевого артикула у меня быть не может.
        Артикул = Число(УА_ОбщийСервер.МаксимальныйНомерАртикула("Префикс-"))+1;
    КонецЦикла;
    Сообщить("Артикул :"+Артикул);
    ЗафиксироватьТранзакцию(); //Возможно эту часть можно опустить , но у меня эта функция во внешней 
                                                           //обработке , поэтому явно завершаю транзакцию. 
КонецПроцедуры



Показать
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
2. nomad_irk 80 31.01.25 16:51 Сейчас в теме
(1)
каким образом с такими проблемами справляются в 1с?

Исключительной транзакционной блокировкой
3. l4h 31.01.25 17:56 Сейчас в теме
(2) Всего справочника? ведь по сути мы только читаем максимальное значение артикула и сам объект не меняем и тут либо блокировать весь справочник, что 100% является не верным решением, либо устанавливать эксклюзивную (исключительную) блокировку на объект содержащий максимальный артикул до завершения транзакции записи текущего элемента. А может есть еще какие-то варианты решения?
4. user2107191 31.01.25 18:33 Сейчас в теме
(3) Не хочешь справочник - пользуй Константу.
5. nomad_irk 80 31.01.25 21:29 Сейчас в теме
Можно использовать константу для хранения значения артикула, в это случае блокировать будет только она.
6. user2107191 31.01.25 21:37 Сейчас в теме
(5) Шас скажет, что артикул не сквозняком по справочнику, а префиксуемый в зависимости от обстоятельств - вида номенклатуры, родителя и т.д.
7. l4h 02.02.25 14:38 Сейчас в теме
(6) так и есть, но не вижу проблемы в этом. Еще не реализовал, но совет выглядит подходящим, спасибо!
Только если мне память не изменяет все константы хранятся в одной таблице и блокироваться будет вся таблица целиком, верно?
10. user2107191 02.02.25 15:03 Сейчас в теме
(7)
константы хранятся в одной таблице и блокироваться будет вся таблица целиком
Это какая-то проблема?
11. miniogn 44 02.02.25 17:11 Сейчас в теме
(7) Вроде разделили. Каждая константа в отдельной таблице.
13. l4h 02.02.25 20:57 Сейчас в теме
(11) Да, Вы правы.
Способ хранения констант в 1С:Предприятие 8 менялся в зависимости от версии платформы. Так, в платформе до версии 8.2.14 (или платформах выше версии, но с включенным режимом совместимости 8.2.13 и ниже), константы хранятся в одной таблице СУБД, начиная с версии 8.2.14, для каждой константы создается своя таблица СУБД. Данное изменение было сделано для увеличения параллельности работы пользователей.
8. l4h 02.02.25 14:51 Сейчас в теме
В общем, решил сделать так: при старте системы получаем список возможных артикулов, для каждого из них формируем текущее максимальное значение и сохраняем в структуру , а дальше при каждом вызове этой процедуры возвращаем +1, не забывая увеличивать максимальный номер в структуре. Если это не полностью исключит возникновение дублей, то как минимум снизит количество таких ошибок, мне думается. Если не поможет, то буду мутить с константами и блокировками.
9. user2107191 02.02.25 15:00 Сейчас в теме
(8) И ты умеешь хранить эту структуру для всех пользователей из разных сеансов одновременно? Или ты научился блокировать структуру от других пользователей?
Чем отличается "хранение и +1 в структуре" от "хранение и +1 в справочнике"?
12. l4h 02.02.25 19:47 Сейчас в теме
(9) Вопрос про блокировку структуры и "для всех сеансов одновременно" хороший. Я почему-то подумал, что оно там разок скомпилируется и будет висеть, типа как синглтон в других языках, но чувствую, ошибся тут. А что касается чем структура от справочника отличается, так ответ очевиден: из справочника мы получаем эти данные запросом и чем больше элементов, тем дольше это все выполняется, а в структуре просто плюсуем и все.
14. l4h 02.02.25 21:57 Сейчас в теме
И по факту даже если мы блокируем константу в исключительном режиме мы все равно можем ее без проблем читать, не можем только изменить ее значение до момента пока первая транзакция не завершится. Так-что все наши рассуждения тут бесполезны в контексте решения поставленной задачи.
проверял след образом: Есть процедура которая получает максимальный номер артикула, добавил в нее блокировку константы, после блокировки установил точку останова. Накидал внешнюю обработку для установки и чтения нужной константы. Запускаю получение нового артикула, выполнение стопорится где нужно, из другого сеанса запускаю обработку, читаю константу - без проблем читается, пытаюсь записать - висит, завершаю транзакцию(снимается блокировка) обработка получает доступ к установке значения константы. Так что вариант не рабочий, к сожалению.
15. l4h 02.02.25 23:06 Сейчас в теме
Вижу только одно решение на текущий момент, при условии, что нигде ничего не упустил из вида: использовать константу в качестве семафора. Заходит в процедуру общего модуля, проверяем нет ли блокировки на константе, если нет, значит никто сейчас не пытается получить артикул, устанавливаем блокировку, формируем новый номер, транзакция завершается, блокировка снимается и тогда уже след поток сможет ее заблокировать. Другие потоки в цикле ждут освобождения. Надеюсь, это ничто не помешает реализовать.
16. l4h 03.02.25 00:03 Сейчас в теме
Все, задачу решил.
Если кому-то еще надо будет, то вот:
//Функция общего модуля которая делает запрос и выбирает максимальный из существующих
Функция МаксимальныйНомерАртикула(Префикс,Характеристика = Ложь) Экспорт

    Попытка
        БлокировкаДанных = Новый БлокировкаДанных;
        БлокировкаКонстанты = БлокировкаДанных.Добавить("Константа.УА_Артикул");
        БлокировкаДанных.Заблокировать();
    Исключение                              
        //Сообщить("Объект уже заблокирован");
        Возврат Ложь;
    КонецПопытки;
//
// тут код получения нужных данных и их возврата
//
КонецФункции


//Код в объекта где требуется получить уникальный номер
Процедура УстановитьАртикул() 
    НачатьТранзакцию(); //Использование транзакций обязательно для использования блокировки объекта
    Артикул = Ложь;
    Пока  НЕ Число(Артикул) Цикл //Артикул возвращается строкой, а строка не может быть преобразована к 
                                                             //булево, поэтому преобразуем к числу, а число легко преобразуется к       
                                                             //булево, нулевого артикула у меня быть не может.
        Артикул = Число(УА_ОбщийСервер.МаксимальныйНомерАртикула("Префикс-"))+1;
    КонецЦикла;
    Сообщить("Артикул :"+Артикул);
    ЗафиксироватьТранзакцию(); //Возможно эту часть можно опустить , но у меня эта функция во внешней 
                                                           //обработке , поэтому явно завершаю транзакцию. 
КонецПроцедуры



Показать
17. пользователь 03.02.25 00:13
Сообщение было скрыто модератором.
...
18. user2107184 03.02.25 06:22 Сейчас в теме
Коллеги, поздравляю - у нас тут новая гениальная обиженка завелась!
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот