#std648
Область применения: управляемое приложение, мобильное приложение, обычное приложение.
1. Ответственным следует считать любое чтение данных, на основе результатов которого производятся изменения в информационной базе или принимаются решения.
Область применения (уточнение): управляемое приложение, обычное приложение.
1.1. Если чтение данных из информационной базы должно быть ответственным, следует производить такое чтение в транзакции с предварительной установкой управляемых блокировок. Например, ответственное чтение данных требуется в следующих случаях:
-
Чтение данных при проведении, для последующего формирования движений;
-
Чтение данных для последующей целостной передачи в другую систему, например в программы типа «Клиент банк»;
-
Выполнение групповой обработки объектов, при реструктуризации данных в обработчиках отложенного и оперативного обновления ИБ (*) * Примечание: перед модификацией ссылочных объектов, обычно, следует устанавливать на них пессимистичные объектные блокировки.
Неправильно:
// 1. Прочитать регистр сведений Запрос = Новый Запрос( "ВЫБРАТЬ РАЗРЕШЕННЫЕ | ЗаметкиПоПредмету.КоличествоЗаметок КАК КоличествоЗаметок |ИЗ | РегистрСведений.ЗаметкиПоПредмету КАК ЗаметкиПоПредмету |ГДЕ | ЗаметкиПоПредмету.Предмет = &Предмет"); Запрос.УстановитьПараметр("Предмет", ПредметЗаметок); Выборка = Запрос.Выполнить().Выбрать(); КоличествоЗаметок = 0; Если Выборка.Следующий() Тогда КоличествоЗаметок = Выборка.КоличествоЗаметок; КонецЕсли; // 2. Записать в регистр сведений НаборЗаписей = РегистрыСведений.ЗаметкиПоПредмету.СоздатьНаборЗаписей(); НаборЗаписей.Отбор.Предмет.Установить(ПредметЗаметок); НоваяЗапись = НаборЗаписей.Добавить(); НоваяЗапись.Предмет = ПредметЗаметок; НоваяЗапись.КоличествоЗаметок = КоличествоЗаметок + 1; НаборЗаписей.Записать();
Правильно:
// 1. Начать транзакцию для пакета из двух операций чтения и записи регистра НачатьТранзакцию();
Попытка // 2. Установить исключительную блокировку на интересующий диапазон записей регистра, // для того чтобы гарантировать, что в момент записи количество заметок не изменилось с момента чтения в каком-либо другом сеансе. БлокировкаДанных = Новый БлокировкаДанных; ЭлементБлокировкиДанных = БлокировкаДанных.Добавить("РегистрСведений.ЗаметкиПоПредмету"); ЭлементБлокировкиДанных.УстановитьЗначение("Предмет", ПредметЗаметок); ЭлементБлокировкиДанных.Режим = РежимБлокировкиДанных.Исключительный; БлокировкаДанных.Заблокировать(); // 3. Прочитать регистр сведений Запрос = Новый Запрос( "ВЫБРАТЬ РАЗРЕШЕННЫЕ | ЗаметкиПоПредмету.КоличествоЗаметок КАК КоличествоЗаметок |ИЗ | РегистрСведений.ЗаметкиПоПредмету КАК ЗаметкиПоПредмету |ГДЕ | ЗаметкиПоПредмету.Предмет = &Предмет"); Запрос.УстановитьПараметр("Предмет", ПредметЗаметок); Выборка = Запрос.Выполнить().Выбрать(); КоличествоЗаметок = 0; Если Выборка.Следующий() Тогда КоличествоЗаметок = Выборка.КоличествоЗаметок; КонецЕсли; // 4. Записать в регистр сведений НаборЗаписей = РегистрыСведений.ЗаметкиПоПредмету.СоздатьНаборЗаписей(); НаборЗаписей.Отбор.Предмет.Установить(ПредметЗаметок); НоваяЗапись = НаборЗаписей.Добавить(); НоваяЗапись.Предмет = ПредметЗаметок; НоваяЗапись.КоличествоЗаметок = КоличествоЗаметок + 1; НаборЗаписей.Записать(); ЗафиксироватьТранзакцию(); Исключение // 5. Если при установке блокировки возникла исключительная ситуация из-за того, что регистр уже заблокирован в другом сеансе (или по другим причинам), // отменить транзакцию и записать сведения об ошибке в журнал регистрации. ОтменитьТранзакцию(); ЗаписьЖурналаРегистрации(НСтр("ru = 'Заметки'", ОбщегоНазначения.КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); ВызватьИсключение; КонецПопытки; |
1.2. В некоторых случаях, ответственное чтение не требуется в силу решаемой прикладной задачи, например:
- Получение данных динамическими списками;
- Поиск данных;
- Формирование большинства отчетов.
В некоторых случаях, ответственное чтение не требуется, так как конкурентная работа с данными маловероятна или полностью исключена, например:
-
Обращение к условно постоянной информации. Например, чтение константы ВалютаРегламентированногоУчета или обращение к учетной политике;
-
Действия, которые гарантированно выполняются в монопольном режиме. Например, в процедурах обновления и первоначального заполнения данных информационной базы;
-
Действия над данными, доступ к которым имеет только один пользователь, поэтому конкурентная работа с ними маловероятна или полностью исключена.
Например, персональные данные, хранящиеся в «разрезе» пользователей;
-
Мобильное приложение, где конкурентная работа с данными маловероятна или полностью исключена.
1.3. В большинстве случаев, при выполнении чтения в обработчиках событий связанных с модификацией данных, весь код обработчика выполняется в рамках системной транзакции, которая открыта платформой, и явно открывать новую транзакцию не требуется.
Например, в системной транзакции выполняются обработчики модулей объектов и соответствующие им подписки на события:
Подробнее – см. документацию к платформе 1С:Предприятие.
Область применения (уточнение): управляемое приложение, обычное приложение.
2. Выбор: исключительная или разделяемая блокировка
2.1. Если в транзакции производится ответственное чтение данных с их последующим изменением, необходимо установить исключительную управляемую блокировку (до выполнения чтения). В противном случае возможно возникновение взаимоблокировки.
Пример установки исключительной блокировки (без открытия транзакции – в предположении, что ранее уже была открыта системная транзакция):
// 1. Установить исключительную блокировку для ответственного чтения объекта с целью его дальнейшего изменения Блокировка = Новый БлокировкаДанных; ЭлементБлокировки = Блокировка.Добавить("Справочник.Приказы"); ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказСсылка); ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный; // можно не указывать, т.к. по умолчанию Исключительный Блокировка.Заблокировать();
// 2. Получить объект для его дальнейшей модификации Объект = ПриказСсылка.ПолучитьОбъект(); Если Объект = Неопределено Тогда // объект может быть уже удален в других сеансах Возврат; КонецЕсли;
// 3. Выполнить блокировку объекта от изменения другими сеансами ЗаблокироватьДанныеДляРедактирования(ПриказСсылка);
// 4. Записать измененный объект Объект.Реквизит = ... Объект.Записать();
2.2. Если в транзакции производится ответственное чтение данных без их последующего изменения (например, для формирования движений), необходимо установить разделяемую блокировку на читаемые данные и исключительную блокировку на изменяемые данные.
Пример установки разделяемой блокировки (без открытия транзакции – в предположении, что ранее уже была открыта системная транзакция):
// 1. Установить разделяемую блокировку для ответственного чтения нескольких связанных объектов Блокировка = Новый БлокировкаДанных; ЭлементБлокировки = Блокировка.Добавить("Справочник.Приказы"); ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказСсылка); ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; Блокировка.Заблокировать();
// 2. Прочитать первый объект - приказ ПриказОбъект = ПриказСсылка.ПолучитьОбъект();
// 3. Прочитать второй объект – пользователя (автора приказа) Блокировка = Новый БлокировкаДанных; ЭлементБлокировки = Блокировка.Добавить("Справочник.Пользователи"); ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказОбъект.Автор); ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; Блокировка.Заблокировать();
АвторПриказа = ПриказОбъект.Автор.ПолучитьОбъект(); |
См. также