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

1. shaykhelov 31.03.22 10:17 Сейчас в теме
приветствую!

Есть клиент-серверная база 1с 8.3 с управляемым режимом блокировок как для конфигурации так и объектов.
Как добиться пропуск чтения заблокированных данных через запрос "ВЫБРАТЬ ..." не дожидаясь разблокировки?
Для базы mssql определен уровень изоляции Read Commited.

Конкретно, имеем непериодический независимый регистр сведений Заказы с измерением Заказ (тип ссылка, не индексирован) и ресурсом Пользователь (тип ссылка, индексирован):



В регистре куча заказов которые необходимо принимать пользователям. Это определяется по пустому значению Пользователь. Код:


Пользователь = ПараметрыСеанса.ТекущийПользователь;

НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);

Попытка
	

	// чтение
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	Заказы.Заказ КАК Заказ
	|ИЗ
	|	РегистрСведений.Заказы КАК Заказы
	|ГДЕ
	|	Заказы.Пользователь = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)";
	
	РезультатЗапроса = Запрос.Выполнить();
	Если РезультатЗапроса.Пустой() Тогда
		ОтменитьТранзакцию();
		Возврат Ложь; // нет свободных заказов
	КонецЕсли;
	
	ВыборкаЗапроса = РезультатЗапроса.Выбрать();
	ВыборкаЗапроса.Следующий(); // заказ получен
	
	
	// блокировка
	
	Блокировка = Новый БлокировкаДанных;
	
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.Заказы");
	ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
	ЭлементБлокировки.УстановитьЗначение("Заказ", ВыборкаЗапроса.Заказ);

	Блокировка.Заблокировать();
	

	// запись
	
	Заказы = РегистрыСведений.Заказы.СоздатьНаборЗаписей();
	Заказы.Отбор.Заказ.Установить(ВыборкаЗапроса.Заказ);
	
	НоваяЗапись = Заказы.Добавить();
	НоваяЗапись.Заказ = ВыборкаЗапроса.Заказ;
	НоваяЗапись.Пользователь = Пользователь;
	
	Заказы.Записать();
	
	ЗафиксироватьТранзакцию();

	
Исключение
	
	ОтменитьТранзакцию();
	ВызватьИсключение;
	Возврат Ложь; // заказ не принят
	
КонецПопытки;


Возврат Истина; // заказ принят

Показать



Представляем что в регистре есть N свободных заказов.
В первом сеансе получили Заказ №1, заблокировали, и в отладчике поставили паузу на строке ЗафиксироватьТранзакцию(), то есть в регистре есть не зафиксиролванные изменения.
Во втором сеансе получаем ожидание на строке Блокировка.Заблокировать(), которое длится до момента разблокировки его первым сеансом (фиксация или отмена).

Возвращаясь к вопросу по запросу ВЫБРАТЬ во втором сеансе, как пропустить заблокированный Заказ №1 и взять на обработку Заказ №2 при выполнении строки Запрос.Выполнить()?
И верно ли мое понимание что это проблема грязного чтения? Так как во втором сеансе запрос использует отбор по пустому пользователю, который изменится первым сеансом или не изменится.
И какому виду использования блокировок будет относиться реализация данной задачи, транзакционным или объектным?

Вообще на самом деле нет необходимости получать заказы последовательно. Заказ №1 может забрать третий сеанс после момента отмена транзакции первым сеансом.
Цель максимально быстро получать и принимать заказы типовыми средствами платформы.
Прикрепленные файлы:
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
3. VictorRGB2 14 31.03.22 10:39 Сейчас в теме
(1) по идее попытка заблокировать уже заблокированный объект приведет к исключению
может выбирать не первые 1, а несколько и циклом перебирать через попытку заблокировать
- успешно - никто еще не схватил и можно работать
- вывались в исключение - значит уже заблокировали в другой сессии, идем к следующему в запросе
4. shaykhelov 31.03.22 11:24 Сейчас в теме
(3)
попытка заблокировать уже заблокированный объект приведет к исключению

Это приводит к ожиданию. Если строку:
Блокировка.Заблокировать();

завернуть в:
Попытка
	Блокировка.Заблокировать();
Исключение
	Сообщить("не удалось заблокировать");
	Возврат Ложь;
КонецПопытки;

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

может выбирать не первые 1, а несколько и циклом перебирать через попытку заблокировать

По моему это не эффективно
5. VictorRGB2 14 31.03.22 11:54 Сейчас в теме
(4) ну так-то да, с блокировками регистров все сложнее, чем с теми же справочниками
есть вариант "через Ж" - сделать свой регистр сведений и писать туда, что заблокировали вот этот заказ, после снятия блокировки запись удалять
и проверять, а заблокирован ли уже текущей заказ или еще нет
10. starik-2005 3090 31.03.22 16:55 Сейчас в теме
(4)
только после разблокировки первым сеансом
Правда? А нафига тогда это вообще сделали? )))
Вообще, всегда можно заюзать файловую блокировку в качестве мьютекса: https://infostart.ru/1c/articles/384485/
15. shaykhelov 01.04.22 18:33 Сейчас в теме
(10)
Правда? А нафига тогда это вообще сделали? )))
Вообще, всегда можно заюзать файловую блокировку в качестве мьютекса: https://infostart.ru/1c/articles/384485/

Блокировка была установлена для запрета получения этого заказа другими сеансами, без ожидания разблокировки.
Тут не получение данных как остаток или цена для дальнейших расчетов.
6. shaykhelov 31.03.22 13:09 Сейчас в теме
(5)
есть вариант "через Ж" - сделать свой регистр сведений и писать туда, что заблокировали вот этот заказ, после снятия блокировки запись удалять


Сеанс 1 получил заказ 1, добавил в свой регистр (ЗаказыДоп) новую запись и зафиксировал об этом.
Второй сеанс пытается этот же полученный заказ 1 добавить в регистр ЗаказыДоп, на которое ему будет отказ, из-за существующей записи.
Далее он (второй сеанс) берет заказ 2, который в этот момент принят третьем сеансом. Представьте высоконагруженную систему, где не только много пользователей, но и объем заказов. Длительное ожидание сеансов обеспечена. Не учитывая дополнительные затраты на двойную чтение/запись для второго регистра.

А если:
и проверять, а заблокирован ли уже текущей заказ или еще нет

то проблема наследуется и для этого регистра
7. VictorRGB2 14 31.03.22 13:21 Сейчас в теме
(6) представляю, потому и вариант "через Ж..." ))
еще, как вариант
определить пользователя приоритеты, Вася 1, Петя 2, Клава 3 и т.д. и перебирать заказы согласно приоритетам
если пользователь Вася, то берет первый заказ, если Петя, то берет второй, если Клава, то берет третий и т.д. с сортировкой по чему там можно, чтобы всегда одинаково выходило в списке заказов
ну и еще смотреть, работает ли Вася сейчас, чтобы можно было при случае сменить приоритетность для Пети и всем остальным соответственно

или по аналоги с приоритетами. получать заказы и Васе - все с 1 по 5, Пете с 6 по 10 и т.д

все это будет подразумевать одно обработку для всех активных пользователей и алгоритм немного замороченный будет, но как варианты на уровне мозгового штурма имею право быть
8. Sashares 35 31.03.22 14:27 Сейчас в теме
(1)Не понимаю смысла обсуждения, и возникающей проблемы, если честно.
Регистр блокируется на время записи одной записи.
Неужели это настолько заметно в работе?

Когда запись в первом сеансе выполнится, во втором сеансе запрос вернет уже следующий свободный заказ. Так в чем проблема то выражается?
9. shaykhelov 31.03.22 15:49 Сейчас в теме
(8)
Неужели это настолько заметно в работе?

Этого пока не произошло, так как разработка в процессе определения ее архитектуры.
Но при моделировании данной ситуации проблема возникает.

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

На самом деле, дождавшись фиксации транзакции сеанса 1, перезапишет данные своими, то есть - Заказ №1, Пользователь №2

Так в чем проблема то выражается?

Проблемы наверно и не было бы если уровень понимания как работают транзакционные блокировки и как ими управлять были бы более ясны. О чем и уточняю у знающих
11. starik-2005 3090 31.03.22 16:58 Сейчас в теме
(9)
О чем и уточняю у знающих
С точки зрения 1С, то архитектура контроля остатков описывается в модуле набора записей регистра, где проверяется, достаточно ли остатка, и если недостаточно, то система генерит соответствующее исключение. Это ровно то, как предлагает решать вопрос 1С.
13. shaykhelov 01.04.22 08:31 Сейчас в теме
(11)
Это ровно то, как предлагает решать вопрос 1С

направите на источник?
14. starik-2005 3090 01.04.22 10:49 Сейчас в теме
12. shaykhelov 31.03.22 23:05 Сейчас в теме
В 1C + MSSQL (без перевода в версионник) возможно реализовать аналог хинта Oracle SKIP LOCKED?

Пока придерживаюсь использование данных менеджера блокировок 1С для исключения заблокированных заказов в запросе условием не в списке элементов объекта Блокировка, наподобие ВЫБРАТЬ ... ГДЕ Заказ НЕ В (&Заблокированные) ? Так как есть такое, что в ситуации при открытой транзакции запрос не использует NOLOCK.
Оставьте свое сообщение

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