#std648¶
Ответственное чтение данных¶
1.¶
Ответственным считается любое чтение, по результатам которого:
- изменяются данные в информационной базе;
- принимаются бизнес-решения, влияющие на последующие изменения.
1.1.¶
Если чтение должно быть ответственным, выполняйте его в транзакции с предварительной установкой управляемых блокировок.
Типичные сценарии:
- чтение данных при проведении с последующим формированием движений;
- чтение для целостной передачи во внешнюю систему;
- групповая обработка и реструктуризация данных при обновлениях.
Для ссылочных объектов перед изменением данных, как правило, дополнительно используйте объектные блокировки. См. #std490: Блокировка данных объекта для редактирования из кода.
Неправильно
// 1. Прочитать регистр сведений
Запрос = Новый Запрос(
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ЗаметкиПоПредмету.КоличествоЗаметок КАК КоличествоЗаметок
|ИЗ
| РегистрСведений.ЗаметкиПоПредмету КАК ЗаметкиПоПредмету
|ГДЕ
| ЗаметкиПоПредмету.Предмет = &Предмет");
Запрос.УстановитьПараметр("Предмет", ПредметЗаметок);
Выборка = Запрос.Выполнить().Выбрать();
КоличествоЗаметок = 0;
Если Выборка.Следующий() Тогда
КоличествоЗаметок = Выборка.КоличествоЗаметок;
КонецЕсли;
// 2. Записать в регистр сведений
НаборЗаписей = РегистрыСведений.ЗаметкиПоПредмету.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Предмет.Установить(ПредметЗаметок);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Предмет = ПредметЗаметок;
НоваяЗапись.КоличествоЗаметок = КоличествоЗаметок + 1;
НаборЗаписей.Записать();
Правильно
// 1. Начать транзакцию для пакета из чтения и записи
НачатьТранзакцию();
Попытка
// 2. Установить исключительную блокировку на интересующий диапазон записей
БлокировкаДанных = Новый БлокировкаДанных;
ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрСведений.ЗаметкиПоПредмету");
ЭлементБлокировки.УстановитьЗначение("Предмет", ПредметЗаметок);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
БлокировкаДанных.Заблокировать();
// 3. Прочитать данные
Запрос = Новый Запрос(
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ЗаметкиПоПредмету.КоличествоЗаметок КАК КоличествоЗаметок
|ИЗ
| РегистрСведений.ЗаметкиПоПредмету КАК ЗаметкиПоПредмету
|ГДЕ
| ЗаметкиПоПредмету.Предмет = &Предмет");
Запрос.УстановитьПараметр("Предмет", ПредметЗаметок);
Выборка = Запрос.Выполнить().Выбрать();
КоличествоЗаметок = 0;
Если Выборка.Следующий() Тогда
КоличествоЗаметок = Выборка.КоличествоЗаметок;
КонецЕсли;
// 4. Записать данные
НаборЗаписей = РегистрыСведений.ЗаметкиПоПредмету.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Предмет.Установить(ПредметЗаметок);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Предмет = ПредметЗаметок;
НоваяЗапись.КоличествоЗаметок = КоличествоЗаметок + 1;
НаборЗаписей.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
1.2.¶
В ряде задач ответственное чтение не требуется.
Например:
- получение данных динамическими списками;
- поиск данных;
- формирование большинства отчетов;
- чтение условно постоянной информации (например, учетной политики, служебных констант);
- действия в монопольных сценариях (обновление и первичное заполнение ИБ);
- действия с персональными данными, где конкурентный доступ практически исключен;
- мобильное приложение, где конкурентная работа маловероятна.
1.3.¶
Во многих обработчиках событий модификации данных платформа уже открывает системную транзакцию. Отдельную транзакцию в этих случаях обычно открывать не нужно.
Это относится, например, к обработчикам:
- #std464: Обработчик события ПередЗаписью;
- #std465: Обработчик события ПриЗаписи;
- #std752: Обработчик события ПередУдалением.
2.¶
Выбор между исключительной и разделяемой блокировкой зависит от того, будут ли изменяться прочитанные данные.
2.1.¶
Если после ответственного чтения данные изменяются, устанавливайте исключительную управляемую блокировку до чтения. Это снижает риск взаимоблокировок.
Пример исключительной блокировки
// 1. Установить исключительную блокировку для ответственного чтения
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Приказы");
ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказСсылка);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
// 2. Получить объект для дальнейшей модификации
Объект = ПриказСсылка.ПолучитьОбъект();
Если Объект = Неопределено Тогда
Возврат;
КонецЕсли;
// 3. Заблокировать объект от изменения и записать
ЗаблокироватьДанныеДляРедактирования(ПриказСсылка);
Объект.Реквизит = ...;
Объект.Записать();
2.2.¶
Если данные читаются ответственно, но не изменяются (например, только для формирования движений), используйте:
- разделяемую блокировку для читаемых данных;
- исключительную блокировку для данных, которые будут изменяться.
Пример разделяемой блокировки
// 1. Установить разделяемую блокировку для чтения связанных объектов
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Приказы");
ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказСсылка);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
Блокировка.Заблокировать();
// 2. Прочитать приказ
ПриказОбъект = ПриказСсылка.ПолучитьОбъект();
// 3. Прочитать автора приказа
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Пользователи");
ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказОбъект.Автор);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
Блокировка.Заблокировать();
АвторПриказа = ПриказОбъект.Автор.ПолучитьОбъект();
См. также¶
- #std460: Использование управляемого режима блокировки
- #std659: Общие сведения об избыточных блокировках
- #std783: Транзакции: правила использования