[ Нюансы платформы 1С:Предприятие 8 ] – Как работает свойство БлокироватьДляИзменения

Начнем так: свойство БлокироватьДляИзменения – ничего не блокирует.

Хотя казалось бы – ровно для этого и существует :)

Еще один пример того, что можно искренне считать, что понимаешь как что-то работает – и не догадываться о заблуждении :))

Как работает свойство БлокироватьДляИзменения набора записей регистра накопления и бухгалтерии, известно далеко не всем специалистам по 1С.

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

С другой стороны, КАК это работает, понимают немногие. Показательно будет привести цитату из справки по БлокироватьДляИзменения:

Устанавливает режим, при котором в процессе записи набора будет установлена управляемая блокировка для всех комбинаций измерений в соответствии с записями набора записей.
На самом деле никакую блокировку это свойство не устанавливает! Для чего же так пишут справке? Сложно сказать – возможно, чтобы не усложнять жизнь начинающим разработчикам :)

В результате это приводит к неправильному использованию данного инструмента для блокировок. В этой статье докопаемся до истины и покажем внутренние детали реализации этого механизма платформы «1С:Предприятие 8.3».

Для того чтобы точно понять всю статью, необходимо знать, что такое механизм разделения итогов. Этому механизму посвящена
отдельная статья на нашем сайте.
Начнем с того, что работа свойства БлокироватьДляИзменения отличается для платформы 8.2 и 8.3. Поэтому рассмотрим 2 сценария.

Использование платформы “1С:Предприятие 8.2” и MS SQL Server

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

Если у регистра накопления с остатками товаров включено разделение итогов, можем получить следующую ситуацию:

Рисунок 1. Схема взаимной блокировки

В представленной ситуации 2 пользователя списывают товар «Стол» со склада «Основной», при этом на складе осталось всего 10 столов.

Так как включено разделение итогов, то оба пользователя параллельно делают движения в таблице итогов, накладывая при этом исключительную управляемую блокировку и X-блокировку СУБД на свои строки. Блокировка будет наложена по полям Склад + Товар + Разделитель, и так как разделитель (splitter) разный, то обе блокировки установятся успешно.

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

Запрос к регистру пытается прочитать все строки, где склад равен «Основной» и товар равен «Стол», без условия по разделителю. При чтении запрос накладывает S-блокировку СУБД.

Иванов может прочитать свою строку, но не может прочитать строку, которую занял пользователь Петров (так как S и X-блокировки не совместимы). В итоге Иванов ждет Петрова. Петров, в свою очередь, может прочитать свою строку, но не может прочитать строку, занятую Ивановым, и тоже встает в очередь.

На схеме синие стрелки показывают успешно наложенные блокировки, красные показывают ожидание на блокировке.

В результате мы получаем взаимную блокировку: Иванов ждет Петрова, а Петров ждет Иванова. Как решить эту проблему, рассмотрим чуть позже. А сейчас перейдем к следующему сценарию.

Отметим, что взаимоблокировки не было бы, если бы режим разделения итогов регистра был отключен. Но, во-первых, режим разделения итогов в общем случае положительно влияет на производительность. Во-вторых, нужно всегда делать устойчивые решения, чтобы при неаккуратных действиях ничего не сломалось :)

Использование платформы “1С:Предприятие 8.3” или использование в качестве СУБД версионника

Сейчас мы рассмотрим сценарий, когда используется платформа 8.3 без режима совместимости с 8.2. Либо когда в качестве СУБД выступает версионник (PostgreSQL, Oracle) – не важно, с какой платформой и в каком режиме.

Кратко отметим, что особенность СУБД версионника в том, что при чтении он не блокирует данные. При использовании 8.3 без режима совместимости с 8.2, MS SQL Server тоже может работать как версионник.

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

Рисунок 2. Схема получения отрицательных остатков

Как исправить проблемы?

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

Чтобы не допустить этих проблем, как раз и было придумано свойство набора записей регистров накопления и бухгалтерии – БлокироватьДляИзменения.

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

Следует отметить что блокировка будет наложена вне зависимости от значения данного свойства. Если БлокироватьДляИзменения имеет значение «Истина», то блокировка будет без учета разделителя, иначе – с учетом разделителя. По умолчанию значение свойства БлокироватьДляИзменения равно «Ложь».

Допустим программист внес исправления в код:

Движения.ТоварыНаСкладах.БлокироватьДляИзменения=Истина; Движения.Записать();

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

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

Рассмотрим поведение системы, если использовать данное свойство.

Рисунок 3. Схема работы при “БлокироватьДляИзменения=Истина”

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

При этом ожидание будет происходить на управляемых блокировках, то есть на сервере 1С. Сервер СУБД даже не будет «знать» о том, что транзакция Петрова ожидает своей очереди.

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

Несколько вопросов и заблуждений по теме

Часто нам задают вопросы по использованию свойства БлокироватьДляИзменения. Рассмотрим наиболее популярные из них.

Вопрос 1

Почему БлокироватьДляИзменения не устанавливают в истину в документе «Приходная накладная»? Ведь если я перепровожу документ ПриходнаяНакладная, то должен блокировать поля, по которым был приход, иначе можно товар списать в минус. Пример: было – Стул 2 шт, перепровожу, меняя Стул на Тумбу, и в этот момент списываю Стул в минус.

Ответ

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

Вопрос 2

Нужно ли использовать БлокироватьДляИзменения в файловом режиме?

Ответ

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

Вопрос 3

Нужно ли устанавливать БлокироватьДляИзменения при очистке движений?

Ответ

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

Вопрос 4

Нужно ли использовать свойство БлокироватьДляИзменения при автоматических блокировках?

Ответ
При попытке использовать БлокироватьДляИзменения в автоматическом режиме блокировок система выдаст сообщение об ошибке: «Ошибка записи! Блокировка для изменения запрещена для автоматического режима блокировки». Данное свойство можно использовать только для управляемого режима блокировок.

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

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

Выводы

Свойство набора записей БлокироватьДляИзменения само по себе ничего не блокирует, оно лишь определяет, будет ли в момент записи при блокировке учитываться разделитель или нет.

Следует использовать данное свойство только при выполнении всех 3 условий:

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

Надеемся, теперь механика работы платформы будет ясна и белых пятен в знаниях специалистов 1С станет меньше :)

Более детально эта тема раскрыта в курсе:

Поддержка – до 4 месяцев. Объем курса – 35 учебных часов.

Об авторе

Автор статьи – Андрей Бурмистров

E-mail: andbkt@mail.ru

Skype: Andreynikus

VK: https://vk.com/andreynikus

Андрей Бурмистров – автор и тренер курса «Ускорение и оптимизация систем на 1С:Предприятие 8.3 и подготовка на 1С:Эксперт по технологическим вопросам»

PDF-версия статьи для участников группы ВКонтакте

Мы ведем группу ВКонтакте – http://vk.com/kursypo1c.

Если Вы еще не вступили в нее – сделайте это сейчас, и в блоке ниже (на этой странице) появятся ссылки на скачивание материалов.


Статья в PDF-форматеСтатья в PDF-формате
Вы можете скачать эту статью в формате PDF по следующей ссылке: Ссылка доступна для зарегистрированных пользователей)

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

24 комментариев к “[ Нюансы платформы 1С:Предприятие 8 ] – Как работает свойство БлокироватьДляИзменения

  1. Сергей сказал:

    Слышал что данное свойство так же устанавливает блокировку на те сочетания значений измерений которые были сформированы “предыдущими” движениями документа. То есть предположим у нас есть проведенный документ, и при перепроведении пользователь поменял состав табличной части. В результате БлокироватьДляИзменения “наложит блокировку” на те движения которые были записаны и те которые были ранее. Так ли это?

    • Андрей Бурмистров сказал:

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

  2. Симонов Иван сказал:

    Добрый вечер, спасибо за статью.
    Прошу вас уточнить, какая логика получения значения остатка при Запрос.Выполнить() в случае включенного разделителя и использования версионника (рис.2)?
    Пользователи получат сразу две записи (с разделителем)? Или каждый получит свою разделенную запись? (Иванов получит 4, а Петров -5).
    Мне непонятен принцип успешного прохождения контроля отрицательных остатков в этом случае.

    • Андрей Бурмистров сказал:

      Благодаря включенному разделению итогов, мы можем одновременно записать в регистр одинаковые значения по набору измерений, например одновременно списать один товар с одного склада. В момент записи строки накладывается X блокировка.
      При использовании версионирования, если транзакция пытается прочитать строку заблокированную X блокировкой, то будет прочитана версия строки до наложения X блокировки.
      В нашем случае Иванов прочитает остаток 4 (10-6), Петров прочитает остаток 5 (10-5). В результате обе транзакции успешно сделают движения т.к. включен разделитель, и обе пройдут контроль остатков, ведь каждая из транзакций думает что остатка хватает.
      Если же разделитель (дополнительную колонку Splitter) не учитывать, поставив БлокироватьДляИзменения=Истина, то параллельной записи одинаковых значений по набору измерений уже не получится, что и демонстрирует рисунок 3. Ведь в этом случае получается что мы пишем данные одновременно в одну строку, а это можно делать только по очереди.
      В результате мы приходим к тому, что при контроле остатков запись в регистр по совпадающим значениям набора измерений регистра, можно делать только последовательно.
      Если остались вопросы, пишите.

  3. GarDmi сказал:

    Спасибо за статью.
    Слегка некорректное название свойства и отсутствие информации со стороны 1С…
    Следовало бы назвать это свойство, например: “СнятьКонтрольРазделенияИтоговПриЗаписи”.

    • Андрей Бурмистров сказал:

      Возможно название связано с тем, что в автоматическом режиме для предотвращения взаимоблокировки, при старом способе контроля остатков, использовалась опция запроса ДЛЯ ИЗМЕНЕНИЯ. А свойство БлокироватьДляИзменения выполняет примерно ту же функцию. Это лишь предположение, правду мы вряд ли когда-нибудь узнаем :)

  4. ZaytsevStepan сказал:

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

    • Андрей Бурмистров сказал:

      Если значения измерений разные, тогда запись пройдет параллельно.

      • ZaytsevStepan сказал:

        Блокировки не нужны значит, если стоит режим “Управляемых блокировок”. Платформа все сама сделает?
        У нас в базе документоборота 1.4 частые блокировки на запись в регистр сведений.
        Был использован способ через запись менеджерЗаписи, изменил на наборЗаписи.
        Реквизиты там БизнесПроцесс и Завершен(булево).
        Второй вопрос, что блокировки возникали при создание новых процессов. Почему тогда они могли возникать, когда БизнесПроцес новый и значит блокировки быть не должно,или при записи в непереодический РС надо как то самим управлять ими?
        Спасибо за ответы.

        • Андрей Бурмистров сказал:

          Если контроль остатков идет после записи, тогда явные управляемые блокировки ставить не нужно, они и так будут установлены при записи. Если контроль до записи, тогда надо будет ставить явные управляемые блокировки. Рекомендую вам ознакомиться с этими статьями: http://курсы-по-1с.рф/news/2017-02-15-two-programming-articles-update/

          По словесному описанию я ничего не могу сказать по поводу расследования блокировок. Ставьте сервис анализа блокировок или ЦУП, снимайте данные тогда будет что обсуждать.
          При создании нового элемента, блокировок никаких нет, они появляются при записи этого объекта в базу данных. Опять же пока нет данных от инструментов, ничего нельзя сказать.

          • ZaytsevStepan сказал:

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

      • Сергей К. сказал:

        А если база файловая? На ней же блокируется вся таблица, правильно я помню/понимаю?
        Т.е. для файловой базы при записи в один регистр, даже если измерения разные, мешающие блокировки будут в любом случае ?
        Надо переходить на SQL?

  5. gosn1ck сказал:

    Спасибо!
    Осталось только понять логику разработчиков УТ и ERP. Флаг “Разрешить разделение итогов” то стоит то не стоит … а в модуле набора записей БлокироватьДляИзменения выставляется в Истину…

    • Юрий Закутасов сказал:

      Добрый день.
      Тоже интересует этот вопрос.

      Почему 1С ставит флаг “БлокироватьДляИзменения” в истину, хотя «Разрешить разделение итогов» отсутствует. (Розница 2.2 – РН “ТоварыНаСкладах”)

      • Андрей Бурмистров сказал:

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

  6. Сергей К. сказал:

    Спасибо, интересно!
    Подскажите, а почему на рис.1 у Петрова в зеленой строке количество минус 5?

    • Андрей Бурмистров сказал:

      Таблица отображает таблицу итогов регистра накопления. Было 10 шт. товара, Иванов списал 6 в строке стало 4. Параллельно Петров списывал 5 шт. и т.к. разделитель включен, вместо попытки обновления записи захваченной Ивановым, добавилась новая запись со значением -5.

  7. Дмитрий сказал:

    Спасибо за статью. То чего действительно не хватало для полноты картины. Одним пробелом меньше в голове=)

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

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

Мы используем файлы cookies, чтобы сделать сайт удобнее.
Продолжая просмотр сайта, Вы соглашаетесь с их использованием.
Подробнее