Перейти к содержанию
#std648

Ответственное чтение данных

1.

Ответственным считается любое чтение, по результатам которого:

  • изменяются данные в информационной базе;
  • принимаются бизнес-решения, влияющие на последующие изменения.
1.1.

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

Типичные сценарии:

  • чтение данных при проведении с последующим формированием движений;
  • чтение для целостной передачи во внешнюю систему;
  • групповая обработка и реструктуризация данных при обновлениях.

Для ссылочных объектов перед изменением данных, как правило, дополнительно используйте объектные блокировки. См. #std490: Блокировка данных объекта для редактирования из кода.

Неправильно

// 1. Прочитать регистр сведений
Запрос = Новый Запрос(
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |   ЗаметкиПоПредмету.КоличествоЗаметок КАК КоличествоЗаметок
    |ИЗ
    |   РегистрСведений.ЗаметкиПоПредмету КАК ЗаметкиПоПредмету
    |ГДЕ
    |   ЗаметкиПоПредмету.Предмет = &Предмет");
Запрос.УстановитьПараметр("Предмет", ПредметЗаметок);
Выборка = Запрос.Выполнить().Выбрать();

КоличествоЗаметок = 0;
Если Выборка.Следующий() Тогда
    КоличествоЗаметок = Выборка.КоличествоЗаметок;
КонецЕсли;

// 2. Записать в регистр сведений
НаборЗаписей = РегистрыСведений.ЗаметкиПоПредмету.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Предмет.Установить(ПредметЗаметок);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Предмет = ПредметЗаметок;
НоваяЗапись.КоличествоЗаметок = КоличествоЗаметок + 1;
НаборЗаписей.Записать();

Правильно

// 1. Начать транзакцию для пакета из чтения и записи
НачатьТранзакцию();

Попытка
    // 2. Установить исключительную блокировку на интересующий диапазон записей
    БлокировкаДанных = Новый БлокировкаДанных;
    ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрСведений.ЗаметкиПоПредмету");
    ЭлементБлокировки.УстановитьЗначение("Предмет", ПредметЗаметок);
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    БлокировкаДанных.Заблокировать();

    // 3. Прочитать данные
    Запрос = Новый Запрос(
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ
        |   ЗаметкиПоПредмету.КоличествоЗаметок КАК КоличествоЗаметок
        |ИЗ
        |   РегистрСведений.ЗаметкиПоПредмету КАК ЗаметкиПоПредмету
        |ГДЕ
        |   ЗаметкиПоПредмету.Предмет = &Предмет");
    Запрос.УстановитьПараметр("Предмет", ПредметЗаметок);
    Выборка = Запрос.Выполнить().Выбрать();

    КоличествоЗаметок = 0;
    Если Выборка.Следующий() Тогда
        КоличествоЗаметок = Выборка.КоличествоЗаметок;
    КонецЕсли;

    // 4. Записать данные
    НаборЗаписей = РегистрыСведений.ЗаметкиПоПредмету.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Предмет.Установить(ПредметЗаметок);
    НоваяЗапись = НаборЗаписей.Добавить();
    НоваяЗапись.Предмет = ПредметЗаметок;
    НоваяЗапись.КоличествоЗаметок = КоличествоЗаметок + 1;
    НаборЗаписей.Записать();

    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;
1.2.

В ряде задач ответственное чтение не требуется.

Например:

  • получение данных динамическими списками;
  • поиск данных;
  • формирование большинства отчетов;
  • чтение условно постоянной информации (например, учетной политики, служебных констант);
  • действия в монопольных сценариях (обновление и первичное заполнение ИБ);
  • действия с персональными данными, где конкурентный доступ практически исключен;
  • мобильное приложение, где конкурентная работа маловероятна.
1.3.

Во многих обработчиках событий модификации данных платформа уже открывает системную транзакцию. Отдельную транзакцию в этих случаях обычно открывать не нужно.

Это относится, например, к обработчикам:

2.

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

2.1.

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

Пример исключительной блокировки

// 1. Установить исключительную блокировку для ответственного чтения
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Приказы");
ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказСсылка);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();

// 2. Получить объект для дальнейшей модификации
Объект = ПриказСсылка.ПолучитьОбъект();
Если Объект = Неопределено Тогда
    Возврат;
КонецЕсли;

// 3. Заблокировать объект от изменения и записать
ЗаблокироватьДанныеДляРедактирования(ПриказСсылка);
Объект.Реквизит = ...;
Объект.Записать();
2.2.

Если данные читаются ответственно, но не изменяются (например, только для формирования движений), используйте:

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

Пример разделяемой блокировки

// 1. Установить разделяемую блокировку для чтения связанных объектов
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Приказы");
ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказСсылка);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
Блокировка.Заблокировать();

// 2. Прочитать приказ
ПриказОбъект = ПриказСсылка.ПолучитьОбъект();

// 3. Прочитать автора приказа
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.Пользователи");
ЭлементБлокировки.УстановитьЗначение("Ссылка", ПриказОбъект.Автор);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
Блокировка.Заблокировать();

АвторПриказа = ПриказОбъект.Автор.ПолучитьОбъект();
См. также
Проверки

#acc:1327 #acc:1328

Источник

https://its.1c.ru/db/v8std#content:648