Чтение и запись наборов записей.
В самом начале своей работы как разработчика, неизбежно приходилось сталкиваться с задачами записи регистров сведений. У наборов записей есть методы "Прочитать()", "Записать()". Ну казалось бы все просто. Один метод читает, другой записывает. Да и кому придет в головку читать данные регистра сведений объектной техникой, когда можно прочитать запросом? Но поработав какое-то время, понял, что есть нюансы. Про них и поговорим.
Для начала начнем немного издалека, и поговорим про управляемые блокировки. Кстати, хороший вопрос для собеседования кандидатам: зачем вообще придумали управляемые блокировки ведь раньше (8.1) жили без них и все прекрасно работало. Предлагаю задуматься над этим вопросом. Вернемся к управляемым блокировкам. Они бывают "разделяемые" и "исключительные". "Разделяемые" - совместимы между собой (можно читать в двух параллельных транзакциях), "Исключительные" - не совместимы с друг с другом, а также с разделяемыми.
Также важно понимать, что управляемые блокировки могут быть установлены только в рамках транзакции, и держаться всегда до конца транзакции (в отличии от блокировок СУБД в определенных режимах изоляции).
Вернемся же к регистрам. Когда мы читаем данные методом набора записей "Прочитать()", сервер 1С неявно накладывает управляемую разделяемую блокировку на прочитанные данные. Поясню на примере:
Если регистр сведений "ОсновнойДоговорКонтрагента", с измерением "Контрагент", и ресурсом "Договор". В момент чтения, будет наложена управляемая разделяемая блокировка.
НаборЗаписей = РегистрыСведений.ОсновнойДоговорКонтрагента.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Контрагент.Установить(Контрагент);
НаборЗаписей.Прочитать();
В каких же случаях нам может потребоваться накладывать разделяемую управляемую блокировку? Тут необходимо познакомиться еще с одним термином, который называется "Ответственное чтение". Что это такое?
Ответственное чтение - это чтение, при котором мы на 100% должны быть уверены, что после прочтения данные не изменятся. В нашем примере если у меня есть алгоритм, который производит действия с основным договором (например получает основной договор контрагента, получает его сумму и отправляет на почту ответственному сотруднику информацию по остатку лимита основного договора), то в процессе выполнения рассылки, другой сотрудник может зайти и поменять основной договор в регистре. В таком случае будут отправлены некорректные данные.
Значит перед рассылкой нам нужно позаботится о том, чтобы данные которые мы прочитали не были изменены. Это можно сделать либо через чтение в объектной технике, либо через установку явной управляемой блокировки через метод "БлокировкаДанных".
Тут мы подходим в плотную к проблематике к которой я наконец-то добрался. Когда встает задача записать данные в регистр, можно встретить следующий код:
НаборЗаписей = РегистрыСведений.ОсновнойДоговорКонтрагента.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Контрагент.Установить(Контрагент);
НаборЗаписей.Прочитать();
НаборЗаписей.Очистить();
// код по добавлению строк в набор записей
НаборЗаписей.Записать();
Как вы думаете какая проблема в коде выше 👆? А проблема в том, что данный код может вызвать взаимоблокировку по причине недостаточного уровня блокировки ресурса. Мы сначала читаем, а затем пишем. И если в двух параллельных сеансах попытаться поменять основной договор, то можем словить взаимоблокировку. Эти строчки абсолютно не нужны в данном примере:
НаборЗаписей.Прочитать();
НаборЗаписей.Очистить();
Набор и так будет перезаписан, читать и очищать его не нужно. Поэтому более правильно тут будет сразу записать набор:
НаборЗаписей = РегистрыСведений.ОсновнойДоговорКонтрагента.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Контрагент.Установить(Контрагент);
// код по добавлению строк в набор записей
НаборЗаписей.Записать();
Если было интересно ставьте 🔥 буду делать больше технических постов.
>>Click here to continue<<