vk fb tw rss

Вся правда про свойство «БлокироватьДляИзменения»

Правда про свойство "БлокироватьДляИзменения"

Мотивацией к написанию данной статьи, послужило большое количество заблуждений касаемо свойства «БлокироватьДляИзменения».
Большая часть материалов в сети, посвящена либо управляемым блокировкам, либо режиму разделения итогов, свойство «БлокироватьДляИзменения» затрагивается лишь частично без конкретики, в итоге у многих возникают вопросы при его использовании.
Давайте разберемся что это за зверь и зачем он вообще нужен.
 

 

 Болтовня ничего не стоит. Покажите мне код.

 

Что бы понять материал данной статьи, нужно хорошо знать и понимать 2 вещи:

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

2. Новая методика контроля остатков (остатки контролируются после записи)

 

Режим разделения итогов очень полезен в том случае, если не нужно делать контроль остатков по регистру т.к. можно параллельно записывать данные с одинаковым набором измерений.
Если по регистру необходимо всегда контролировать остатки, то лучше не использовать режим разделения итогов т.к. выигрыша в параллельности он не дает.
Но как быть, если например у регистра есть 2 регистратора, и один документ использует контроль остатков, а второй нет?
В этом случае нам как раз и пригодится свойство набора записей регистров накопления и бухгалтерии «БлокироватьДляИзменения».

Начнем с того, что использовать «БлокироватьДляИзменения» имеет смысл, только если выполняются все следующие условия:

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

 

Если хотя бы одно из 3-х условий не выполняется, то нет смысла использовать «БлокироватьДляИзменения».
Поэтому все сказанное ниже применимо только если выполняются все три условия.

 

А что это свойство делает?

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

Некоторых смущает такая формулировка, а именно слова «отключает разделитель итогов по записываемому набору измерений». Что бы было понятнее скажу другими словами, если мы ставим «БлокироватьДляИзменения» в «Истина» то управляемая блокировка накладывается без учета разделителя.

На мой взгляд эти две формулировки одинаковы по смыслу, но на экзамене 1С:Эксперт рекомендую использовать вторую формулировку «управляемая блокировка накладывается без учета разделителя», хотя в сущности они описывают одно и тоже явление.

А поподробнее?

Тут необходимо расписать каждую фразу, что бы исключить неправильную трактовку.

«… оно отключает разделитель итогов»

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

Т.е блокировка будет наложена в любом случае (независимо от того используете вы свойство или нет), но при использовании «БлокироватьДляИзменения» блокировка будет наложена без учета разделителя итогов.

 

А зачем вообще отключать разделитель итогов?

Если не отключить разделитель итогов, то платформа накладывает управляемую блокирвку по ключу Склад+Товар+Разделитель.

В результате возможны следующие последствия:

  • При использовании СУБД блокировочника — возможна взаимоблокировка.
  • При использовании версионника — возможно списание остатков в минус.

 

Давайте разберем эти случаи подробнее.

Если используется блокировочник.

В случае с блокировочником, deadlock получается довольно просто, две транзакции параллельно записывают свои данные по одному набору измерений, платформа это позволяет т.к. используется разделитель итогов. После этого обе транзакции хотят проверить остатки, а для этого нужны все строки по ключу Склад+Товар (т.е. без учета разделителя). В итоге ни одна из транзакций не может прочитать все строки, т.к. часть строк захвачена другой транзакцией (разделитель «мешает» захватить все строки).

Схема этой взаимоблокировки представлена в таблице.

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

В этом случае, по своему назначению, «БлокироватьДляИзменения» это аналог параметра «ДЛЯ ИЗМЕНЕНИЯ» в запросе чтения остатков в автоматическом режиме, только работает иначе.

Если включить «БлокироватьДляИзменения», то мы отключим разделитель итогов, и при записи сразу будет наложена управляемая блокировка Склад+Товар, и транзакция 2 не сможет добавить вторую строку, т.к. данный набор измерений будет уже заблокирован.
При использовании «БлокироватьДляИзменения», блокировка ключа Склад+Товар является следствием отключения разделителя итогов для предотвращения  дедлока. Можно сказать, что это своего рода полезный побочный эффект.

Но даже если бы мы не использовали БлокироватьДляИзменения (и рискнули нарваться на deadlock), то остатки в минус все равно бы не списались, т.к. все нужные строки по ключу Склад+Товар (без учета разделителя) были бы заблокированы запросом остатков.

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

 

Если используется версионник

В этом случае, заблокированные строки первой транзакции, никак не помешают 2-й транзакции прочитать остатки (т.к. в версионнике пишущие не блокируют читающих).
Вторая транзакция спокойно прочитает старую версию данных (версию на момент начала первой транзакции) и спишет остаток в минус. Что бы этого не допустить нужна управляемая блокировка на уровне 1С.
Если поставить БлокироватьДляИзменения = Истина, мы как раз получим такую блокировку, и данные будут заблокированы на уровне платформы.

 

«по записываемому набору измерений»

Разделитель отключается только для данного набора измерений.

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

 

Пример:

Допустим что одновременно встретились 6 транзакций и попытались одновременно записать данные в регистр, при этом разделитель итогов естественно включен.
Первые 2 транзакции делают расход и контролируют остатки, другие 4 делают приход и контроль остатков им не нужен.

Тогда мы получим такую картину.

Пример использования БлокироватьДляИзменения

Транзакция 1 оказалась на долю секунды быстрее всех и в момент записи данных установила исключительную управляемую блокировку без учета разделителя итогов (т.к. БлокироватьДляИзменения = Истина).
Транзакции 2 и 6 ждут Транзакцию 1, т.к. набор измерений у них одинаковый.
В данном случае без разницы какое значение «БлокироватьДляИзменения» установлено для транзакций 2 и 6, важно что набор измерений одинаковый, и он уже заблокирован, так что они не смогут параллельно записать свои данные.
Транзакции 3 и 4 успешно записали свои данные параллельно, т.к. включен разделитель (БлокироватьДляИзменения = Ложь).
Транзакция 5 успешно записала данные параллельно, т.к. используется отличный от транзакции 1 набор измерений.

 

«начиная с момента записи до конца транзакции»

Разделитель итогов отключается только в тот момент, когда начинается запись данных регистра и действует до тех пор, пока не закончится транзакция проведения документа.
Это значит, что включить данное свойство можно в любом месте кода, но действовать оно начнет только в момент записи данных в регистр.
При этом свойство действует, пока не завершилась вся транзакция, т.е. если запись в регистр завершилась, а транзакция продолжается, то свойство так же продолжает работать.
Таким образом, если произойдет откат транзакции, свойство автоматически примет значение «Ложь»

 

А что будет, если установить БлокироватьДляИзменения = Истина для регистра, у которого выключен режим разделения итогов? 

Ровным счетом ничего, не будет даже ошибки, просто данная строка кода будет проигнорирована.

 

А как же явные управляемые блокировки, они теперь не нужны?

Да, это еще один плюс данного свойства. При его использовании не нужно писать явные управляемые блокировки, достаточно одной строки Движения.НужныйРегистр.БлокироватьДляИзменения = Истина, это делает код компактнее и читабельнее. Но стоит помнить что использовать данное свойство можно только при соблюдении трех условий описанных в начале статьи.

 

А можно пример?

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Процедура ОбработкаПроведения(Отказ, Режим)
 
    // регистр ОстаткиТоваров Расход
    Движения.ОстаткиТоваров.Записывать = Истина;
    Для Каждого ТекСтрокаТабличнаяЧасть Из ТабличнаяЧасть Цикл
        Движение = Движения.ОстаткиТоваров.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
        Движение.Период = Дата;
        Движение.Склад = Склад;
        Движение.Товар = ТекСтрокаТабличнаяЧасть.Товар;
        Движение.Количество = ТекСтрокаТабличнаяЧасть.Количество;
    КонецЦикла;
 
    Движения.ОстаткиТоваров.БлокироватьДляИзменения = Истина;
    Движения.Записать();
    // Далее код проверки остатков
КонецПроцедуры

Строку «Движения.ОстаткиТоваров.БлокироватьДляИзменения = Истина;» можно писать в любом месте процедуры, для удобства лучше это делать в конце.

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

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

 

Выводы:

1. Данное свойство нужно использовать, только если соблюдаются все 3 условия:

  • транзакция выполняется в управляемом режиме
  • у регистра включен режим разделения итогов
  • используется новая методика контроля остатков (остатки контролируются после записи)

2. Несмотря на название, свойство ничего не блокирует (блокировка происходит при записи в любом случае), оно отключает режим разделения итогов, следствием этого является блокировка всех нужных записей (без учета разделителя).

3. При использовании «БлокироватьДляИзменения», явные управляемые блокировки ставить не нужно.

 

Друзья, давайте не будем теряться на просторах интернета!  Я предлагаю вам получать на e-mail извещения о публикации новых статей и материалов, таким образом вы всегда будете в курсе самых интересных новостей!

 



Лучшие материалы по теме

Расскажите своим друзьям
Вам ничего не стоит, а им будет интересно
Подпишитесь на обновления
Ваш e-mail: * Ваше имя: *


Обсудить Вконтакте


Обсудить в Facebook

3 комментария: Вся правда про свойство «БлокироватьДляИзменения»

  • Вопрос по поводу: блокировочника и версионника(сли имеется ввиду блокировки на уровне СУБД и менеджер блокировок сервера 1с). В статье написано что в одном случае будет взаимоблокировка а в другом списание в минус.
    Насколько я понимаю в управляемом режиме блокировками всегда занимается сервер 1с значит возможна только одна ситуация — списание в минус(взаимоблокировка в данном случае была бы возможна в автоматическом режиме).
    Поясните пожалуйста этот момент.

    • > В статье написано что в одном случае будет взаимоблокировка а в другом списание в минус
      Да, это будет в том случае, если мы используем управляемые блокировки.

      >Насколько я понимаю в управляемом режиме блокировками всегда занимается сервер 1с значит возможна только одна ситуация — списание в минус
      Нет, в упр. режиме для блокировочника будет взаимоблокировка, для версионника списание в минус.

      В данной статье разбираются ситуации только для управляемого режима управления блокировкой данных, если у нас автоматический режим тогда свойство БлокироватьДляИзменения не будет работать вообще, и как следствие будут те же самые проблемы т.е. взаимоблокировка для блокировочников и отр. остатки для версионников, только здесь уже мы эти проблемы никак не устраним (придется отключать разделитель итогов).
      Таким образом в автоматическом режиме разделитель итогов нужно включать только тогда, когда у нас по регистру всегда отсутствует контроль остатков т.к. у нас нет возможности использовать свойство БлокироватьДляИзменения потому что нет управляемых блокировок.
      Для прояснения картины рекомендую вам на бумаге нарисовать схемы возможных проблем при использовании разделителя, тогда все сразу станет намного понятнее.

  • Спасибо вам.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *