Неустранимый конфликт блокировок чтение и запись РС

1. user645801_yyyuuu123q 16.04.24 14:41 Сейчас в теме
Всем привет друзья.
Подскажите пожалуйста, правильно ли Я делаю?
При работе, очень часто появляется ошибка.
Сделал так, но на сколько это правильно?


Процедура ЗарегистрироватьПакетОбъектов(ПакетДанных)
	
	Попытка
		НаборЗаписей = РегистрыСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени.СоздатьНаборЗаписей();
		НачатьТранзакцию();   
		// Блокировка данных
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени");
		Блокировка.Заблокировать();	
		НаборЗаписей.Прочитать();
		
		ЗафиксироватьТранзакцию(); 
		
		тзнВрем = НаборЗаписей.Выгрузить();
		
		ЕстьИзменения = Ложь;
		
		Для каждого ТекСтрока Из ПакетДанных Цикл
			
			НайденныеСтроки = тзнВрем.НайтиСтроки(Новый Структура("Объект, НастройкаПодключения, ТипОбъекта, ПодчиненныйОбъект", ТекСтрока.Объект, ТекСтрока.НастройкаПодключения, ТекСтрока.ТипОбъекта, ТекСтрока.ПодчиненныйОбъект)); 
			Если НайденныеСтроки.Количество() = 0 Тогда
				
				НоваяЗапись = НаборЗаписей.Добавить();
				НоваяЗапись.Объект 					= ТекСтрока.Объект;    
				НоваяЗапись.ПодчиненныйОбъект 		= ТекСтрока.ПодчиненныйОбъект;  	
				НоваяЗапись.НастройкаПодключения 	= ТекСтрока.НастройкаПодключения;
				НоваяЗапись.ТипОбъекта 				= ТекСтрока.ТипОбъекта;  	
				
				ЕстьИзменения = Истина;
				
			КонецЕсли;
		КонецЦикла;
	Исключение
		ОтменитьТранзакцию();
	КонецПопытки;
	
	Если ЕстьИзменения Тогда   
		Попытка      
			НачатьТранзакцию();   
			// Блокировка данных
			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени");
			Блокировка.Заблокировать();			
			НаборЗаписей.Записать();
			ЗафиксироватьТранзакцию();  
		Исключение
			ОтменитьТранзакцию();
		КонецПопытки;
	КонецЕсли;
	
	ЗапускРегистрацииИзменений();			
	
КонецПроцедуры 
Показать



Ошибка при вызове метода контекста (Записать)
{Битрикс24КомплексУТ ОбщийМодуль.Б24_КС_РегистрацияИзмененийВызовСервера.Модуль(828)}:НаборЗаписей.Прочитать();
{Битрикс24КомплексУТ ОбщийМодуль.Б24_КС_РегистрацияИзмененийВызовСервера.Модуль(740)}:ЗарегистрироватьПакетОбъектов(ПакетДанных);
{Битрикс24КомплексУТ ОбщийМодуль.Б24_КС_РегистрацияИзмененийВызовСервера.Модуль(20)}:ЗарегистрироватьИзменения(Источник, Замещение);
{ОбщийМодуль.ПроведениеДокументов.Модуль(1653)}:Документ.Движения.Записать();
{ОбщийМодуль.ПроведениеДокументов.Модуль(230)}:ПровестиДокумент(Документ, Отказ, ДопПараметры);
{Документ.ЗаказКлиента.МодульОбъекта(808)}:ПроведениеДокументов.ОбработкаПроведенияДокумента(ЭтотОбъект, Отказ);
{ОбщийМодуль.ОбщегоНазначенияУТКлиент.Модуль(1862)}:Результат = Форма.Записать(ПараметрыЗаписи);
{Документ.ЗаказКлиента.Форма.ФормаДокумента.Форма(7819)}:ОбщегоНазначенияУТКлиент.ОбработатьЗаписьОбъектаВФорме(ЭтотОбъект, ПараметрыДляЗаписи);

[ОшибкаВоВремяВыполненияВстроенногоЯзыка]
по причине:
Ошибка при выполнении обработчика - 'ОбработкаПроведения'
по причине:
Ошибка при вызове метода контекста (Записать)
[ОшибкаВоВремяВыполненияВстроенногоЯзыка]
по причине:
Ошибка при выполнении обработчика - 'ПередЗаписью'
по причине:
Ошибка при вызове метода контекста (Прочитать)
[ОшибкаВоВремяВыполненияВстроенногоЯзыка]
по причине:
Конфликт блокировок при выполнении транзакции:
Неустранимый конфликт блокировок
Показать


Ошибка вроде этой
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
2. Sashares 34 16.04.24 14:59 Сейчас в теме
(1) Зачем тут 2 транзакции и 2 блокировки? Это не верно.

Зачем блокировать весь регистр?
Надо блокировать только по тем записям, которые есть в ТЗ ПакетДанных.
Поместить ТЗ ПакетДанных в запрос во временную таблицу. Выбрать только те данные, которых нет в регистре.
Записать менеджером записей.

Все это делается в одной транзакции.
user645801_yyyuuu123q; +1 Ответить
3. user645801_yyyuuu123q 16.04.24 15:00 Сейчас в теме
(2) Да понимаю, пока сделал как делается. А дальше хотел бы услышать рекомендации коллег
4. Sashares 34 16.04.24 15:03 Сейчас в теме
(3)Рекомендации даны в предыдущем комментарии.
5. user645801_yyyuuu123q 16.04.24 15:06 Сейчас в теме
(4)а что делать когда происходит чтение?
7. Sashares 34 16.04.24 15:32 Сейчас в теме
(5)У вас при проведении этот регистр тоже пишется? То есть где-то еще, помимо этого кода.
8. user645801_yyyuuu123q 17.04.24 10:17 Сейчас в теме
(7)Нет, Только в этом расширении, обращение идет от разных документов
9. Sashares 34 17.04.24 11:08 Сейчас в теме
(8)Возможно проблема именно в этом. Вы устанавливаете блокировку на весь регистр.
Исправьте код по рекомендациям 2, проблема скорее всего уйдет.
10. user645801_yyyuuu123q 17.04.24 14:06 Сейчас в теме
(9)Сделал как в 2, проблема при чтении не решилась
11. Sashares 34 17.04.24 14:25 Сейчас в теме
12. user645801_yyyuuu123q 17.04.24 14:29 Сейчас в теме
(11)
Процедура ЗарегистрироватьПакетОбъектов(ПакетДанных)
	
    ПакетДанныхДляЗаписи = ПакетДанныхДляРегистрацииИзменений(); 
	
	НаборЗаписей = РегистрыСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени.СоздатьНаборЗаписей();
	НаборЗаписей.Прочитать();
	тзнВрем = НаборЗаписей.Выгрузить();
	
	ЕстьИзменения = Ложь;
	
	Для каждого ТекСтрока Из ПакетДанных Цикл	
		НайденныеСтроки = тзнВрем.НайтиСтроки(Новый Структура("Объект, НастройкаПодключения, ТипОбъекта, ПодчиненныйОбъект", ТекСтрока.Объект, ТекСтрока.НастройкаПодключения, ТекСтрока.ТипОбъекта, ТекСтрока.ПодчиненныйОбъект)); 
		Если НайденныеСтроки.Количество() = 0 Тогда	
			НоваяЗапись = ПакетДанныхДляЗаписи.Добавить();
			НоваяЗапись.Объект 					= ТекСтрока.Объект;    
			НоваяЗапись.ПодчиненныйОбъект 		= ТекСтрока.ПодчиненныйОбъект;  	
			НоваяЗапись.НастройкаПодключения 	= ТекСтрока.НастройкаПодключения;
			НоваяЗапись.ТипОбъекта 				= ТекСтрока.ТипОбъекта;  	
			
			ЕстьИзменения = Истина;	
		КонецЕсли;
	КонецЦикла;
	
	Если ПакетДанныхДляЗаписи.Количество() > 0 Тогда
		//	
		Для Каждого ТекСтрока Из тзнВрем Цикл
			//
			НоваяЗапись = ПакетДанныхДляЗаписи.Добавить();
			НоваяЗапись.Объект 					= ТекСтрока.Объект;    
			НоваяЗапись.ПодчиненныйОбъект 		= ТекСтрока.ПодчиненныйОбъект;  	
			НоваяЗапись.НастройкаПодключения 	= ТекСтрока.НастройкаПодключения;
			НоваяЗапись.ТипОбъекта 				= ТекСтрока.ТипОбъекта;  	
			//
		КонецЦикла;	
		//   
		ЕстьИзменения = Истина;	
	КонецЕсли;	
	
	Если ЕстьИзменения Тогда 
		Попытка
			Для Каждого ТекСтрока Из ПакетДанныхДляЗаписи Цикл 
				НачатьТранзакцию(); 
				БлокировкаДанных = Новый БлокировкаДанных();
				ЭлементБлокировкиДанных = БлокировкаДанных.Добавить("РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени");
				ЭлементБлокировкиДанных.УстановитьЗначение("Объект",ТекСтрока.Объект);
				ЭлементБлокировкиДанных.УстановитьЗначение("ПодчиненныйОбъект",ТекСтрока.ПодчиненныйОбъект);
				ЭлементБлокировкиДанных.УстановитьЗначение("НастройкаПодключения",ТекСтрока.НастройкаПодключения);
				ЭлементБлокировкиДанных.УстановитьЗначение("ТипОбъекта",ТекСтрока.ТипОбъекта);   
				ЭлементБлокировкиДанных.Режим = РежимБлокировкиДанных.Исключительный;
				БлокировкаДанных.Заблокировать();
				
				ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем = РегистрыСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени.СоздатьМенеджерЗаписи();
				ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.Объект 					= ТекСтрока.Объект;    
				ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.ПодчиненныйОбъект 		= ТекСтрока.ПодчиненныйОбъект;  	
				ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.НастройкаПодключения 	= ТекСтрока.НастройкаПодключения;
				ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.ТипОбъекта 				= ТекСтрока.ТипОбъекта;  
				
				ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.Записать();
				ЗафиксироватьТранзакцию();
			КонецЦикла;
		Исключение
			ОтменитьТранзакцию();
		КонецПопытки;
	КонецЕсли;
	ЗапускРегистрацииИзменений();			
	
КонецПроцедуры  

Показать
13. Sashares 34 17.04.24 14:47 Сейчас в теме
(12) А если так:
Процедура ЗарегистрироватьПакетОбъектов(ПакетДанных)
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ПакетДанных", ПакетДанных);
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ТТ.Объект КАК Объект,
	|	ТТ.ПодчиненныйОбъект КАК ПодчиненныйОбъект,
	|	ТТ.ТипОбъекта КАК ТипОбъекта,
	|	ТТ.НастройкаПодключения КАК НастройкаПодключения
	|ПОМЕСТИТЬ ТабПакета
	|ИЗ
	|	&ПакетДанных КАК ТТ
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	ТТ.Объект,
	|	ТТ.ПодчиненныйОбъект,
	|	ТТ.ТипОбъекта,
	|	ТТ.НастройкаПодключения
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ
	|	ТабПакета.Объект КАК Объект,
	|	ТабПакета.ПодчиненныйОбъект КАК ПодчиненныйОбъект,
	|	ТабПакета.ТипОбъекта КАК ТипОбъекта,
	|	ТабПакета.НастройкаПодключения КАК НастройкаПодключения
	|ИЗ
	|	ТабПакета КАК ТабПакета
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени КАК ТТ
	|		ПО ТабПакета.Объект = ТТ.Объект
	|			И ТабПакета.ПодчиненныйОбъект = ТТ.ПодчиненныйОбъект
	|			И ТабПакета.ТипОбъекта = ТТ.ТипОбъекта
	|			И ТабПакета.НастройкаПодключения = ТТ.НастройкаПодключения
	|ГДЕ
	|	ТТ.Объект ЕСТЬ NULL"; 
	
	РезультатЗапроса = Запрос.Выполнить();
	
    БлокировкаДанных = Новый БлокировкаДанных();
    ЭлементБлокировкиДанных = БлокировкаДанных.Добавить("РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени");
	ЭлементБлокировкиДанных.ИсточникДанных = РезультатЗапроса;
	ЭлементБлокировкиДанных.ИспользоватьИзИсточникаДанных("Объект","Объект");
    ЭлементБлокировкиДанных.ИспользоватьИзИсточникаДанных("ПодчиненныйОбъект","ПодчиненныйОбъект");
    ЭлементБлокировкиДанных.ИспользоватьИзИсточникаДанных("НастройкаПодключения","НастройкаПодключения");
    ЭлементБлокировкиДанных.ИспользоватьИзИсточникаДанных("ТипОбъекта","ТипОбъекта");   
    ЭлементБлокировкиДанных.Режим = РежимБлокировкиДанных.Исключительный;
    	
        НачатьТранзакцию();

	Попытка
		БлокировкаДанных.Заблокировать();
		Выборка = РезультатЗапроса.Выбрать();
		Пока Выборка.Следующий() Цикл
			Запись = РегистрыСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени.СоздатьМенеджерЗаписи();
			Запись.Объект                  = Выборка.Объект;    
			Запись.ПодчиненныйОбъект       = Выборка.ПодчиненныйОбъект;      
			Запись.НастройкаПодключения    = Выборка.НастройкаПодключения;
			Запись.ТипОбъекта              = Выборка.ТипОбъекта;  

			Запись.Записать();
		КонецЦикла;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();	
	КонецПопытки;
	
    ЗапускРегистрацииИзменений();            
    
КонецПроцедуры
Показать


И у регистра режим управления блокировкой данных - Управляемый поставить
15. user645801_yyyuuu123q 17.04.24 14:57 Сейчас в теме
(13)Таблица со старта не типизирована, там составные типы. Если только заранее типизировать, но по читаемости и производительности то на то и выйдет
17. Sashares 34 17.04.24 15:00 Сейчас в теме
19. user645801_yyyuuu123q 17.04.24 15:19 Сейчас в теме
(17) Твое решение крутое, только таблица не типизирована, а типы там составные
21. Sashares 34 17.04.24 15:32 Сейчас в теме
(19)Типизировать не предлагать?
Описание типов для создания колонок можно получить из метаданных регистра:
Метаданные.РегистрыСведений.ИмяРегистра.Ресурсы.ИмяРесурса.Тип
Метаданные.РегистрыСведений.ИмяРегистра.Измерения.ИмяИзмерения.Тип
22. user645801_yyyuuu123q 17.04.24 15:42 Сейчас в теме
(21) Там составной же тип, прям легко не получиться.
24. Sashares 34 17.04.24 15:45 Сейчас в теме
(22)Еще раз.
ОписаниеТиповРесурса = Метаданные.РегистрыСведений.ИмяРегистра.Ресурсы.ИмяРесурса.Тип;
ОписаниеТиповИзмерения = Метаданные.РегистрыСведений.ИмяРегистра.Измерения.ИмяИзмерения.Тип; 

Вот так можно получить описание типов со всеми типами, которые заданы в регистре для измерения/ресурса соответственно.

Как использовать:
Таблица.Колонки.Добавить(ИмяКолонки, ОписаниеТиповРесурса );


Куда еще легче?
25. user645801_yyyuuu123q 17.04.24 15:46 Сейчас в теме
(24) Спасибо мужик, Я не знал. Я тут просто хардкодить начал по всем типам Если => ИначеЕсли => ...
26. user645801_yyyuuu123q 17.04.24 16:07 Сейчас в теме
(24) На много, завтра протестирую, скажу как работает
18. user645801_yyyuuu123q 17.04.24 15:00 Сейчас в теме
(13)
(13)  
	НаборЗаписей = РегистрыСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем­ени.СоздатьНаборЗаписей();


Вот когда это происходим, тут уже одна запись есть, та что в доке который запустил весь процесс
29. user645801_yyyuuu123q 18.04.24 15:19 Сейчас в теме
(13)
 |    ТТ.Объект НЕ ЕСТЬ NULL"; 


Тут Не надо поставить
30. Sashares 34 18.04.24 15:29 Сейчас в теме
(29)Нет, не надо.
Запрос возвращает те данные, которых еще нет в регистре.
Чтобы не перезаписывать то, что уже есть еще раз.
31. user645801_yyyuuu123q 20.04.24 13:34 Сейчас в теме
(30)Этот регистр всегда пустой, с него регламентное задание все убирает
32. Sashares 34 20.04.24 16:44 Сейчас в теме
(31)Ох, чел.
В изначальном коде 2 транзакции.
В 1 читается набор записей регистра. В цикле проверятся, что строка Пакета данных нет в наборе записей, который прочитался. И в прочитанный набор записей добавляются только те данные Пакета данных, которых еще в нем нет. И записывается весь набор который прочитался.

Мой код запросом отсекает те данные, которые в регистре уже есть, и записывает только те, которых в нем нет.

На этом я дискуссию заканчиваю. Делай как хочешь, тебя никто не заставляет и не уговаривает.
А то бисер у меня уже закончился.
user645801_yyyuuu123q; +1 Ответить
14. user1880116 17.04.24 14:51 Сейчас в теме
(12) Хехе, классик...

Всё это происходит внутри неявной транзакции в обработке проведения:
НаборЗаписей.Прочитать();
Это накладывает разделяемую блокировку на весь регистр
НачатьТранзакцию();
Это игнорируется. Мы уже находимся в транзакции проведения
ЭлементБлокировкиДанных.Режим = РежимБлокировкиДанных.Исключительный;
БлокировкаДанных.Заблокировать();

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

Дедлок готов. Первый процесс прочитал, второй прочитал. Первый хочет записать, но второй держит. Второй хочет записать, но первый держит.

Ходите на курсы, учите матчасть.
16. user645801_yyyuuu123q 17.04.24 14:58 Сейчас в теме
(14) Ты ведь можешь подсказать как выйти из этой ситуации и все. Мы же на форуме, помогаем друг другу. А не самоутверждаемся за счет других
20. user1880116 17.04.24 15:22 Сейчас в теме
(16)
Мы же на форуме, помогаем друг другу

Пункт 7.8. правил https://infostart.ru/about/rules/ :
Infostart.ru не гарантирует, что: сервисы будут соответствовать Вашим требованиям;

Тема блокировок требует подготовки, которой у тебя нет. Поэтому сходить на курсы и изучать матчасть - лучшее для тебя решение.
23. user645801_yyyuuu123q 17.04.24 15:44 Сейчас в теме
(20) Так и скажу: Ребят на курсы быстро сгоняю через 3-4 месяца все сделаю.
А Я думал форум как раз и нужен, обсудить и решить задачу которую ты не знал но ее сделать надо. А в последствии после решения уже идешь на курсы там и что то другое.
Слушай у Меня требований нет, вот ты сходил на курсе и гордишься что знаешь больше.
У Меня единственное требования попросить тебя покинуть тему
27. user1880116 17.04.24 16:28 Сейчас в теме
(23) А ты слова "я" и "меня" по какой причине с заглавной пишешь?
28. user645801_yyyuuu123q 18.04.24 00:57 Сейчас в теме
(27)В школе заставляли а иначе 2.
Привычка осталась, но не думаю что она как то негативно влияет
6. user645801_yyyuuu123q 16.04.24 15:08 Сейчас в теме
Когда читаю, тоже ошибка транзакции
Оставьте свое сообщение

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