Неустранимый конфликт блокировок чтение и запись РС
Всем привет друзья.
Подскажите пожалуйста, правильно ли Я делаю?
При работе, очень часто появляется ошибка.
Сделал так, но на сколько это правильно?
Ошибка вроде этой
Подскажите пожалуйста, правильно ли Я делаю?
При работе, очень часто появляется ошибка.
Сделал так, но на сколько это правильно?
Процедура ЗарегистрироватьПакетОбъектов(ПакетДанных)
Попытка
НаборЗаписей = РегистрыСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем ени.СоздатьНаборЗаписей();
НачатьТранзакцию();
// Блокировка данных
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем ени");
Блокировка.Заблокировать();
НаборЗаписей.Прочитать();
ЗафиксироватьТранзакцию();
тзнВрем = НаборЗаписей.Выгрузить();
ЕстьИзменения = Ложь;
Для каждого ТекСтрока Из ПакетДанных Цикл
НайденныеСтроки = тзнВрем.НайтиСтроки(Новый Структура("Объект, НастройкаПодключения, ТипОбъекта, ПодчиненныйОбъект", ТекСтрока.Объект, ТекСтрока.НастройкаПодключения, ТекСтрока.ТипОбъекта, ТекСтрока.ПодчиненныйОбъект));
Если НайденныеСтроки.Количество() = 0 Тогда
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Объект = ТекСтрока.Объект;
НоваяЗапись.ПодчиненныйОбъект = ТекСтрока.ПодчиненныйОбъект;
НоваяЗапись.НастройкаПодключения = ТекСтрока.НастройкаПодключения;
НоваяЗапись.ТипОбъекта = ТекСтрока.ТипОбъекта;
ЕстьИзменения = Истина;
КонецЕсли;
КонецЦикла;
Исключение
ОтменитьТранзакцию();
КонецПопытки;
Если ЕстьИзменения Тогда
Попытка
НачатьТранзакцию();
// Блокировка данных
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем ени");
Блокировка.Заблокировать();
НаборЗаписей.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
КонецПопытки;
КонецЕсли;
ЗапускРегистрацииИзменений();
КонецПроцедуры
ПоказатьОшибка при вызове метода контекста (Записать)
{Битрикс24КомплексУТ ОбщийМодуль.Б24_КС_РегистрацияИзмененийВызовСервера.Модуль(828)}:НаборЗаписей.Прочитать();
{Битрикс24КомплексУТ ОбщийМодуль.Б24_КС_РегистрацияИзмененийВызовСервера.Модуль(740)}:ЗарегистрироватьПакетОбъектов(ПакетДанных);
{Битрикс24КомплексУТ ОбщийМодуль.Б24_КС_РегистрацияИзмененийВызовСервера.Модуль(20)}:ЗарегистрироватьИзменения(Источник, Замещение);
{ОбщийМодуль.ПроведениеДокументов.Модуль(1653)}:Документ.Движения.Записать();
{ОбщийМодуль.ПроведениеДокументов.Модуль(230)}:ПровестиДокумент(Документ, Отказ, ДопПараметры);
{Документ.ЗаказКлиента.МодульОбъекта(808)}:ПроведениеДокументов.ОбработкаПроведенияДокумента(ЭтотОбъект, Отказ);
{ОбщийМодуль.ОбщегоНазначенияУТКлиент.Модуль(1862)}:Результат = Форма.Записать(ПараметрыЗаписи);
{Документ.ЗаказКлиента.Форма.ФормаДокумента.Форма(7819)}:ОбщегоНазначенияУТКлиент.ОбработатьЗаписьОбъектаВФорме(ЭтотОбъект, ПараметрыДляЗаписи);
[ОшибкаВоВремяВыполненияВстроенногоЯзыка]
по причине:
Ошибка при выполнении обработчика - 'ОбработкаПроведения'
по причине:
Ошибка при вызове метода контекста (Записать)
[ОшибкаВоВремяВыполненияВстроенногоЯзыка]
по причине:
Ошибка при выполнении обработчика - 'ПередЗаписью'
по причине:
Ошибка при вызове метода контекста (Прочитать)
[ОшибкаВоВремяВыполненияВстроенногоЯзыка]
по причине:
Конфликт блокировок при выполнении транзакции:
Неустранимый конфликт блокировок
ПоказатьОшибка вроде этой
По теме из базы знаний
Ответы
Подписаться на ответы
Инфостарт бот
Сортировка:
Древо развёрнутое
Свернуть все
(1) Зачем тут 2 транзакции и 2 блокировки? Это не верно.
Зачем блокировать весь регистр?
Надо блокировать только по тем записям, которые есть в ТЗ ПакетДанных.
Поместить ТЗ ПакетДанных в запрос во временную таблицу. Выбрать только те данные, которых нет в регистре.
Записать менеджером записей.
Все это делается в одной транзакции.
Зачем блокировать весь регистр?
Надо блокировать только по тем записям, которые есть в ТЗ ПакетДанных.
Поместить ТЗ ПакетДанных в запрос во временную таблицу. Выбрать только те данные, которых нет в регистре.
Записать менеджером записей.
Все это делается в одной транзакции.
(11)
Процедура ЗарегистрироватьПакетОбъектов(ПакетДанных)
ПакетДанныхДляЗаписи = ПакетДанныхДляРегистрацииИзменений();
НаборЗаписей = РегистрыСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем ени.СоздатьНаборЗаписей();
НаборЗаписей.Прочитать();
тзнВрем = НаборЗаписей.Выгрузить();
ЕстьИзменения = Ложь;
Для каждого ТекСтрока Из ПакетДанных Цикл
НайденныеСтроки = тзнВрем.НайтиСтроки(Новый Структура("Объект, НастройкаПодключения, ТипОбъекта, ПодчиненныйОбъект", ТекСтрока.Объект, ТекСтрока.НастройкаПодключения, ТекСтрока.ТипОбъекта, ТекСтрока.ПодчиненныйОбъект));
Если НайденныеСтроки.Количество() = 0 Тогда
НоваяЗапись = ПакетДанныхДляЗаписи.Добавить();
НоваяЗапись.Объект = ТекСтрока.Объект;
НоваяЗапись.ПодчиненныйОбъект = ТекСтрока.ПодчиненныйОбъект;
НоваяЗапись.НастройкаПодключения = ТекСтрока.НастройкаПодключения;
НоваяЗапись.ТипОбъекта = ТекСтрока.ТипОбъекта;
ЕстьИзменения = Истина;
КонецЕсли;
КонецЦикла;
Если ПакетДанныхДляЗаписи.Количество() > 0 Тогда
//
Для Каждого ТекСтрока Из тзнВрем Цикл
//
НоваяЗапись = ПакетДанныхДляЗаписи.Добавить();
НоваяЗапись.Объект = ТекСтрока.Объект;
НоваяЗапись.ПодчиненныйОбъект = ТекСтрока.ПодчиненныйОбъект;
НоваяЗапись.НастройкаПодключения = ТекСтрока.НастройкаПодключения;
НоваяЗапись.ТипОбъекта = ТекСтрока.ТипОбъекта;
//
КонецЦикла;
//
ЕстьИзменения = Истина;
КонецЕсли;
Если ЕстьИзменения Тогда
Попытка
Для Каждого ТекСтрока Из ПакетДанныхДляЗаписи Цикл
НачатьТранзакцию();
БлокировкаДанных = Новый БлокировкаДанных();
ЭлементБлокировкиДанных = БлокировкаДанных.Добавить("РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем ени");
ЭлементБлокировкиДанных.УстановитьЗначение("Объект",ТекСтрока.Объект);
ЭлементБлокировкиДанных.УстановитьЗначение("ПодчиненныйОбъект",ТекСтрока.ПодчиненныйОбъект);
ЭлементБлокировкиДанных.УстановитьЗначение("НастройкаПодключения",ТекСтрока.НастройкаПодключения);
ЭлементБлокировкиДанных.УстановитьЗначение("ТипОбъекта",ТекСтрока.ТипОбъекта);
ЭлементБлокировкиДанных.Режим = РежимБлокировкиДанных.Исключительный;
БлокировкаДанных.Заблокировать();
ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем = РегистрыСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем ени.СоздатьМенеджерЗаписи();
ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.Объект = ТекСтрока.Объект;
ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.ПодчиненныйОбъект = ТекСтрока.ПодчиненныйОбъект;
ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.НастройкаПодключения = ТекСтрока.НастройкаПодключения;
ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.ТипОбъекта = ТекСтрока.ТипОбъекта;
ТабПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем.Записать();
ЗафиксироватьТранзакцию();
КонецЦикла;
Исключение
ОтменитьТранзакцию();
КонецПопытки;
КонецЕсли;
ЗапускРегистрацииИзменений();
КонецПроцедуры
Показать
(12) А если так:
И у регистра режим управления блокировкой данных - Управляемый поставить
Процедура ЗарегистрироватьПакетОбъектов(ПакетДанных)
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ПакетДанных", ПакетДанных);
Запрос.Текст =
"ВЫБРАТЬ
| ТТ.Объект КАК Объект,
| ТТ.ПодчиненныйОбъект КАК ПодчиненныйОбъект,
| ТТ.ТипОбъекта КАК ТипОбъекта,
| ТТ.НастройкаПодключения КАК НастройкаПодключения
|ПОМЕСТИТЬ ТабПакета
|ИЗ
| &ПакетДанных КАК ТТ
|
|ИНДЕКСИРОВАТЬ ПО
| ТТ.Объект,
| ТТ.ПодчиненныйОбъект,
| ТТ.ТипОбъекта,
| ТТ.НастройкаПодключения
|;
|
|//////////////////////////////////////////////////////////// ////////////////////
|ВЫБРАТЬ
| ТабПакета.Объект КАК Объект,
| ТабПакета.ПодчиненныйОбъект КАК ПодчиненныйОбъект,
| ТабПакета.ТипОбъекта КАК ТипОбъекта,
| ТабПакета.НастройкаПодключения КАК НастройкаПодключения
|ИЗ
| ТабПакета КАК ТабПакета
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем ени КАК ТТ
| ПО ТабПакета.Объект = ТТ.Объект
| И ТабПакета.ПодчиненныйОбъект = ТТ.ПодчиненныйОбъект
| И ТабПакета.ТипОбъекта = ТТ.ТипОбъекта
| И ТабПакета.НастройкаПодключения = ТТ.НастройкаПодключения
|ГДЕ
| ТТ.Объект ЕСТЬ NULL";
РезультатЗапроса = Запрос.Выполнить();
БлокировкаДанных = Новый БлокировкаДанных();
ЭлементБлокировкиДанных = БлокировкаДанных.Добавить("РегистрСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем ени");
ЭлементБлокировкиДанных.ИсточникДанных = РезультатЗапроса;
ЭлементБлокировкиДанных.ИспользоватьИзИсточникаДанных("Объект","Объект");
ЭлементБлокировкиДанных.ИспользоватьИзИсточникаДанных("ПодчиненныйОбъект","ПодчиненныйОбъект");
ЭлементБлокировкиДанных.ИспользоватьИзИсточникаДанных("НастройкаПодключения","НастройкаПодключения");
ЭлементБлокировкиДанных.ИспользоватьИзИсточникаДанных("ТипОбъекта","ТипОбъекта");
ЭлементБлокировкиДанных.Режим = РежимБлокировкиДанных.Исключительный;
НачатьТранзакцию();
Попытка
БлокировкаДанных.Заблокировать();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Запись = РегистрыСведений.Б24_КС_ТаблицаПроверкиОбъектовНаВыгрузкуВРежимеРеальногоВрем ени.СоздатьМенеджерЗаписи();
Запись.Объект = Выборка.Объект;
Запись.ПодчиненныйОбъект = Выборка.ПодчиненныйОбъект;
Запись.НастройкаПодключения = Выборка.НастройкаПодключения;
Запись.ТипОбъекта = Выборка.ТипОбъекта;
Запись.Записать();
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
КонецПопытки;
ЗапускРегистрацииИзменений();
КонецПроцедуры
ПоказатьИ у регистра режим управления блокировкой данных - Управляемый поставить
(22)Еще раз.
Вот так можно получить описание типов со всеми типами, которые заданы в регистре для измерения/ресурса соответственно.
Как использовать:
Куда еще легче?
ОписаниеТиповРесурса = Метаданные.РегистрыСведений.ИмяРегистра.Ресурсы.ИмяРесурса.Тип;
ОписаниеТиповИзмерения = Метаданные.РегистрыСведений.ИмяРегистра.Измерения.ИмяИзмерения.Тип;
Вот так можно получить описание типов со всеми типами, которые заданы в регистре для измерения/ресурса соответственно.
Как использовать:
Таблица.Колонки.Добавить(ИмяКолонки, ОписаниеТиповРесурса );
Куда еще легче?
(31)Ох, чел.
В изначальном коде 2 транзакции.
В 1 читается набор записей регистра. В цикле проверятся, что строка Пакета данных нет в наборе записей, который прочитался. И в прочитанный набор записей добавляются только те данные Пакета данных, которых еще в нем нет. И записывается весь набор который прочитался.
Мой код запросом отсекает те данные, которые в регистре уже есть, и записывает только те, которых в нем нет.
На этом я дискуссию заканчиваю. Делай как хочешь, тебя никто не заставляет и не уговаривает.
А то бисер у меня уже закончился.
В изначальном коде 2 транзакции.
В 1 читается набор записей регистра. В цикле проверятся, что строка Пакета данных нет в наборе записей, который прочитался. И в прочитанный набор записей добавляются только те данные Пакета данных, которых еще в нем нет. И записывается весь набор который прочитался.
Мой код запросом отсекает те данные, которые в регистре уже есть, и записывает только те, которых в нем нет.
На этом я дискуссию заканчиваю. Делай как хочешь, тебя никто не заставляет и не уговаривает.
А то бисер у меня уже закончился.
(12) Хехе, классик...
Всё это происходит внутри неявной транзакции в обработке проведения:
Это накладывает исключительную блокировку по твоим измерениям.
Дедлок готов. Первый процесс прочитал, второй прочитал. Первый хочет записать, но второй держит. Второй хочет записать, но первый держит.
Ходите на курсы, учите матчасть.
Всё это происходит внутри неявной транзакции в обработке проведения:
НаборЗаписей.Прочитать();
Это накладывает разделяемую блокировку на весь регистр
НачатьТранзакцию();
Это игнорируется. Мы уже находимся в транзакции проведения
ЭлементБлокировкиДанных.Режим = РежимБлокировкиДанных.Исключительный;
БлокировкаДанных.Заблокировать();
БлокировкаДанных.Заблокировать();
Это накладывает исключительную блокировку по твоим измерениям.
Дедлок готов. Первый процесс прочитал, второй прочитал. Первый хочет записать, но второй держит. Второй хочет записать, но первый держит.
Ходите на курсы, учите матчасть.
(16)
Пункт 7.8. правилhttps://infostart.ru/about/rules/ :
Infostart.ru не гарантирует, что: сервисы будут соответствовать Вашим требованиям;
Тема блокировок требует подготовки, которой у тебя нет. Поэтому сходить на курсы и изучать матчасть - лучшее для тебя решение.
Мы же на форуме, помогаем друг другу
Пункт 7.8. правил
Infostart.ru не гарантирует, что: сервисы будут соответствовать Вашим требованиям;
Тема блокировок требует подготовки, которой у тебя нет. Поэтому сходить на курсы и изучать матчасть - лучшее для тебя решение.
(20) Так и скажу: Ребят на курсы быстро сгоняю через 3-4 месяца все сделаю.
А Я думал форум как раз и нужен, обсудить и решить задачу которую ты не знал но ее сделать надо. А в последствии после решения уже идешь на курсы там и что то другое.
Слушай у Меня требований нет, вот ты сходил на курсе и гордишься что знаешь больше.
У Меня единственное требования попросить тебя покинуть тему
А Я думал форум как раз и нужен, обсудить и решить задачу которую ты не знал но ее сделать надо. А в последствии после решения уже идешь на курсы там и что то другое.
Слушай у Меня требований нет, вот ты сходил на курсе и гордишься что знаешь больше.
У Меня единственное требования попросить тебя покинуть тему
Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот