Конфигурация УТ для Украины 2.3 (доработанная много чем), платформа 8.3.8.1784. И вот снова конфликт блокировки транзакций, где около 200 пользователей одновременно блокируют друг друга. Отложенное проведение по партиям уже не помагает, прижало до реализации управляемых блокировок. На основе [необходимо зарегистрироваться для просмотра ссылки] придумал реализовать блокировки по складу следующим образом:
1. Переводим саму конфигурацию на чисто управляемые блокировки. 2. Создаем подписку на событие "ОбработкаПроверкиЗаполнения", источник - ДокументОбъект. 3. Процедура подписки:
//Определения имени пространства для "Последовательность"
Для Каждого ТекПоследовательность Из Последовательности Цикл Если ТекПоследовательность.Принадлежит(Источник.Ссылка) Тогда //Необходимо заблокировать последовательность
Если Метаданные.РегистрыНакопления.Найти(ИмяРегистра) <> Неопределено Тогда ТипРегистра = "РегистрНакопления"; ИначеЕсли Метаданные.РегистрыБухгалтерии.Найти(ИмяРегистра) <> Неопределено Тогда ТипРегистра = "РегистрБухгалтерии"; Иначе ТипРегистра = "РегистрСведений"; КонецЕсли;
Если ТипРегистра <> "" Тогда ЭлементБлокировки = Блокировка.Добавить(ТипРегистра + "." + ИмяРегистра + ".НаборЗаписей"); ЭлементБлокировки.Режим = РежимБлокировки;
Если ТекРегистрДвижения.Измерения.Найти("Склад") <> Неопределено Тогда
Если Источник.Метаданные().Реквизиты.Найти("СкладОрдер") <> Неопределено Тогда ЭлементБлокировки.УстановитьЗначение("Склад", Источник.СкладОрдер); ИначеЕсли Источник.Метаданные().Реквизиты.Найти("Склад") <> Неопределено Тогда ЭлементБлокировки.УстановитьЗначение("Склад", Источник.Склад); ИначеЕсли Источник.Метаданные().Реквизиты.Найти("СкладОтправитель") <> Неопределено Тогда тз = Новый ТаблицаЗначений; тз.Колонки.Добавить("Склад"); строка = тз.Добавить(); строка.Склад = Источник.СкладОтправитель; строка = тз.Добавить(); строка.Склад = Источник.СкладПолучатель; ЭлементБлокировки.ИсточникДанных = тз; ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Склад", "Склад");
КонецЕсли; КонецЕсли;
КонецЕсли;
КонецЦикла;
//Установка блокировки
Попытка Блокировка.Заблокировать(); Исключение ОбщегоНазначения.СообщитьОбОшибке(ОписаниеОшибки(), Отказ, "Не удалось заблокировать объекты"); ВызватьИсключение "Операция не выполнена"; КонецПопытки; КонецПроцедуры
Подписка на "ОбработкаПроверкиЗаполнения" выполняется раньше чем "ПередЗаписью" в модуле объекта. Блокировка работает так: По умолчанию блокируется все без отбора. Но если регистр имеет измерение "Склад", а источник "Склад", "СкладОрдер", "СкладОтправитель" - то устанавливается отбор по складу. Теоретически такая блокировка должна увеличить параллельность. Кто что думает?
Сделал я вот это все. На тестовой базе зашел под двумя пользователями и одновременно запустил перепроведение всех реализаций и там и там, но первый пользователь - все реализации с одного склада "Склад1" второй - "Склад2". Теоретически взаимоблокировок не должно быть. Но постоянно вижу Конфликт блокировки транзакций по регистру партий. В месте где вызывается запрос по партиям и списанным товарам. В запросе по партиям есть отбор по складу, а вот списанные товары не блокируются....
Группа: Основатель
Сообщений: 13948
Из: Киев
Спасибо сказали: 4514 раз
Рейтинг: 3635.6
С блокировками существует 2 проблемы: 1) кто-то отваливается по таймауту, потому что не дожидается освобождения ресурсов 2) кто-то отваливается из-за взаимоблокировок
С блокировками существует 2 проблемы: 1) кто-то отваливается по таймауту, потому что не дожидается освобождения ресурсов 2) кто-то отваливается из-за взаимоблокировок
Группа: Основатель
Сообщений: 13948
Из: Киев
Спасибо сказали: 4514 раз
Рейтинг: 3635.6
Перечитываю много раз что вы написали, но непонятно нифига что у вас происходит. Кроме того вы, видимо, путаете между собой эти две проблемы (о которых я выше писал), считая, что это одно и то же. Вы сейчас запускаете проведение расходных накладных под двумя пользователями по разным складам и у вас в какой-то момент возникают именно взаимоблокировки?
Перечитываю много раз что вы написали, но непонятно нифига что у вас происходит. Кроме того вы, видимо, путаете между собой эти две проблемы (о которых я выше писал), считая, что это одно и то же. Вы сейчас запускаете проведение расходных накладных под двумя пользователями по разным складам и у вас в какой-то момент возникают именно взаимоблокировки?
Да, путаю. Но уже не путаю, уже вроде разобрался в их различии. Именно взаимоблокировки, так как пишет ошибку "... стала жертвой взаимоблокировки". - Значит менеджер взаимоблокировок одну транзакцию принес в жертву.
Но вот незадача: отключил ту процедуру что описал выше, которая осуществляет блокировки. - результат тот же. Блокировок не ставлю - откуда взаимоблокировки?Конфигурация в режиме чисто управляемых блокировок.
Группа: Основатель
Сообщений: 13948
Из: Киев
Спасибо сказали: 4514 раз
Рейтинг: 3635.6
Сейчас у вас конфа стоит в режиме Управляемый, вы проводите под разными пользователями только Расходные накладные и возникает взаимоблокировка? А не видно в каком именно месте в коде?
// Для повышения быстродействия остатки партий получаются различными способами Если СтруктураПараметров.Свойство("ЗакрытиеЗаказовПокупателей") Тогда ЗаполнитьЗапросПартийНаСкладахДляЗакрытияЗаказовПокупателей(Запрос);
ИначеЕсли ОсновнойДокумент <> Неопределено И НЕ СтруктураПараметров.СписыватьПартииРасходнымОрдером И ТипЗнч(ОсновнойДокумент) = Тип("ДокументСсылка.РеализацияТоваровУслуг")тогда // Списание расходным ордером товара реализованного и принятого на ответственное хранение (отложенная отгрузка) ЗаполнитьЗапросПартийНаСкладахДляОтложеннойОтгрузкиУпр(Запрос, ВестиПартионныйУчетПоСкладам);
ИначеЕсли ОсновнойДокумент <> Неопределено тогда // Списание партий по ордерной схеме: // - Списание партий по расходному ордеру // - Перемещение партий по приходному ордеру // - Перемещение партий поступлением товаров и услуг в НТТ // Движения реализации выполняет расходный ордер, движения перемещения выполняет приходный ордер ЗаполнитьЗапросПартийНаСкладахДляСписанияПоОрдернойСхемеУпр(Запрос, ВестиПартионныйУчетПоСкладам, СтратегияСтатусПартии, СпособОценкиМПЗ);
Иначе // Общий случай списания ЗаполнитьЗапросПартийНаСкладахУпр(Запрос, ВестиПартионныйУчетПоСкладам, СтратегияСтатусПартии, СпособОценкиМПЗ);
Если НЕ СтруктураПараметров.ИспользоватьУказаниеСерийНоменклатурыПриРезервировании тогда Запрос.Текст = СтрЗаменить(Запрос.Текст,"ИЛИ ПартииТоваровНаСкладах.СерияНоменклатуры = &ПустаяСерияНоменклатуры", "ИЛИ ПартииТоваровНаСкладах.СерияНоменклатуры = &ПустаяСерияНоменклатуры |ИЛИ СписанныеТовары.КодОперацииПартииТоваров = &КодРезервирование"); Запрос.УстановитьПараметр("КодРезервирование" , СтруктураПараметров.КодыОпераций.РезервированиеПодЗаказ) КонецЕсли;
Если ОсновнойДокумент <> Неопределено Тогда Запрос.УстановитьПараметр("ОсновнойДокумент", ОсновнойДокумент); Иначе Запрос.УстановитьПараметр("ОсновнойДокумент", Регистратор); КонецЕсли;
Если ТипЗнч(Регистратор) = Тип("ДокументСсылка.ОтчетОРозничныхПродажах") или ТипЗнч(Регистратор) = Тип("ДокументСсылка.РеализацияТоваровУслуг") ИЛИ ТипЗнч(Регистратор) = Тип("ДокументСсылка.ПеремещениеТоваров") Тогда //или ТипЗнч(Регистратор) = Тип("ДокументСсылка.ВозвратТоваровПоставщику") Тогда
Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ | СписанныеТовары.НомерСтрокиДокумента КАК НомерСтрокиДокумента, | ПартииТоваровНаСкладах.Номенклатура, | ПартииТоваровНаСкладах.ДокументОприходования КАК ДокументОприходования, | ПартииТоваровНаСкладах.ДокументОприходования.Дата КАК ДокументОприходованияДата, | ПартииТоваровНаСкладах.Склад, | ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры, | ПартииТоваровНаСкладах.СерияНоменклатуры, | ПартииТоваровНаСкладах.Качество, | ПартииТоваровНаСкладах.Заказ, | ПартииТоваровНаСкладах.КоличествоОстаток КАК Количество, | ПартииТоваровНаСкладах.СтоимостьОстаток КАК Стоимость, | ПартииТоваровНаСкладах.СтатусПартии, | ВЫБОР | КОГДА СписанныеТовары.СерияНоменклатуры = ПартииТоваровНаСкладах.СерияНоменклатуры | ТОГДА 0 | ИНАЧЕ 1 | КОНЕЦ КАК ЧислоСерияНоменклатуры, | ВЫБОР | КОГДА СписанныеТовары.ДокументПартии = НЕОПРЕДЕЛЕНО | ТОГДА 0 | ИНАЧЕ ВЫБОР | КОГДА СписанныеТовары.ДокументПартии = ПартииТоваровНаСкладах.ДокументОприходования | ТОГДА 0 | ИНАЧЕ 1 | КОНЕЦ | КОНЕЦ КАК ЧислоДокументОприходования, | ВЫБОР | КОГДА СписанныеТовары.ЗаказПартии = НЕОПРЕДЕЛЕНО | ТОГДА 0 | ИНАЧЕ ВЫБОР | КОГДА ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ | ТОГДА 1 | ИНАЧЕ 0 | КОНЕЦ | КОНЕЦ КАК ЧислоЗаказ, | ВЫБОР | КОГДА ПартииТоваровНаСкладах.СтатусПартии = &НаКомиссию | ТОГДА 1 | ИНАЧЕ 0 | КОНЕЦ КАК ЧислоСтатусПартии |ИЗ | РегистрСведений.СписанныеТовары КАК СписанныеТовары | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ПартииТоваровНаСкладах.Остатки(&Дат, Склад = &Склад) КАК ПартииТоваровНаСкладах | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СписанныеТовары КАК СписанныеТовары1 | ПО СписанныеТовары1.Номенклатура = ПартииТоваровНаСкладах.Номенклатура | ПО СписанныеТовары.Номенклатура = ПартииТоваровНаСкладах.Номенклатура | И СписанныеТовары.ХарактеристикаНоменклатуры = ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры | И (ВЫБОР | КОГДА ПартииТоваровНаСкладах.Качество = &ПустоеКачество | ТОГДА ИСТИНА | ИНАЧЕ ВЫБОР | КОГДА СписанныеТовары.Качество = &ПустоеКачество | ТОГДА ПартииТоваровНаСкладах.Качество = &КачествоНовый | ИНАЧЕ ПартииТоваровНаСкладах.Качество = СписанныеТовары.Качество | КОНЕЦ | КОНЕЦ) | И (ПартииТоваровНаСкладах.Склад = СписанныеТовары.Склад | ИЛИ ПартииТоваровНаСкладах.Склад = &ПустойСклад) | И (ВЫБОР | КОГДА СписанныеТовары.ДопустимыйСтатус1 <> &ПустойСтатус | ИЛИ СписанныеТовары.ДопустимыйСтатус2 <> &ПустойСтатус | ИЛИ СписанныеТовары.ДопустимыйСтатус3 <> &ПустойСтатус | ИЛИ СписанныеТовары.ДопустимыйСтатус4 <> &ПустойСтатус | ТОГДА ПартииТоваровНаСкладах.СтатусПартии = &ПустойСтатус | ИЛИ ПартииТоваровНаСкладах.СтатусПартии = &СтатусПартииПоОрдеру | ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус1 | ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус2 | ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус3 | ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус4 | ИНАЧЕ ИСТИНА | КОНЕЦ) | И (ВЫБОР | КОГДА СписанныеТовары.СписыватьТолькоПоЗаказу = ИСТИНА | ТОГДА ВЫБОР | КОГДА ПартииТоваровНаСкладах.Заказ <> СписанныеТовары.ЗаказПартии | ТОГДА ВЫБОР | КОГДА НЕ СписанныеТовары.ЗаказПартии = НЕОПРЕДЕЛЕНО | ТОГДА ЛОЖЬ | ИНАЧЕ ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ | КОНЕЦ | ИНАЧЕ ИСТИНА | КОНЕЦ | ИНАЧЕ ВЫБОР | КОГДА ПартииТоваровНаСкладах.Заказ <> СписанныеТовары.ЗаказПартии | ТОГДА ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ | ИНАЧЕ ИСТИНА | КОНЕЦ | КОНЕЦ) | И (СписанныеТовары.СерияНоменклатуры = ПартииТоваровНаСкладах.СерияНоменклатуры | ИЛИ ПартииТоваровНаСкладах.СерияНоменклатуры = &ПустаяСерияНоменклатуры | ИЛИ СписанныеТовары.КодОперацииПартииТоваров = &КодРезервирование) |ГДЕ | СписанныеТовары.Регистратор = &ОсновнойДокумент | И СписанныеТовары.Склад = &Склад | И СписанныеТовары1.Регистратор = &Ссылка | |УПОРЯДОЧИТЬ ПО | ЧислоСерияНоменклатуры, | ЧислоДокументОприходования, | ЧислоЗаказ, | ЧислоСтатусПартии, | ДокументОприходованияДата, | ДокументОприходования |ИТОГИ ПО | НомерСтрокиДокумента";
Если ТипЗнч(Регистратор) = Тип("ДокументСсылка.ПеремещениеТоваров") Тогда Запрос.УстановитьПараметр("Склад", Регистратор.СкладОтправитель); Иначе Запрос.УстановитьПараметр("Склад", Регистратор.Склад); КонецЕсли; КонецЕсли;
причем всегда на том же месте ошибка. Запрос выполняется по партиям. На партии стоит отбор по складу. На списанные товары блокировку вообще не ставил. Да и проблема в том что если вообще блокировку не ставить то ошибка та же. Такое впечатление что как то они автоматически ставятся.
Регистр Партии товаров на складах заблокирован в следствии транзакции при групповом проведении документов. Вы хотите во время данной транзакции параллельно запустить еще одно групповое проведение по данному регистру?
В обработке группового проведения, в настройках снять галочку "Выполнять в транзакции".
Я проведение делаю там и там в Запроснику. Выполняю запрос - нахожу все реализации по складу, В обработке результата запроса - перепровожу.
Вообщем может делаю что не так: Есть УТ. Включаю в настройках конфигурации режим блокировок "Управляемый". Дальше что делать, чтобы реализации одновременно проводились по партиям, по разным складам. Как блокировать партии только по конкретному складу?
Разобрался. [необходимо зарегистрироваться для просмотра ссылки]:
Цитата
Управляемый режим позволяет повысить параллельность работы пользователей в клиент-серверном варианте работы за счет использования более низкого уровня изоляции транзакций базы данных (Read Committed). При записи данных в транзакции объекты встроенного языка автоматически блокируют необходимые данные. Разработчику требуется управлять блокировками данных в тех случаях, когда бизнес-логика требует согласованного и целостного чтения данных в транзакции.
То есть, насколько я понял, если не блокировать в коде при управляемом режиме, то конфигурация всеравно блокирует данные но более на низком уровне. Но если блокировать - тогда работает твой код. Следовательно в примере выше я не блокировал регситр сведений "СписанныеТовары". Когда я прописал в коде:
- блокировки исчезли. Мы в СписанныеТовары ничего не пишем - только читаем из него. Если мы его явно в коде не упоминали - он блокировался полностью и исключительно.
Причем блокировка работает почемуто только в ОбработкеПроведения документа. В подписках не работает...
1С Предприятие 8.3, 1С Предприятие 8.2, 1С Предприятие 8.1, 1С Предприятие 8.0, 1С Предприятие 7.7, Литература 1С, Общие вопросы по администрированию 1С, Методическая поддержка 1С - всё в одном месте: на Украинском 1С форуме!