Управляемые блокировки

Общая информация

Приложения хранят данные в СУБД. Любое чтение или запись данных в СУБД выполняются в транзакции.

Транзакция — это неделимая, с точки зрения воздействия на базу данных, последовательность операций манипулирования данными, выполняющаяся по принципу «все или ничего». Она переводит базу данных из одного целостного состояния в другое целостное состояние. Если по каким-либо причинам одно из действий транзакции невыполнимо или произошло какое-либо нарушение работы системы, база данных возвращается в то состояние, которое было до начала транзакции (происходит откат транзакции).

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

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

для этих целей использует одновременно два механизма:

  • Поддержка изоляции транзакций, реализуемая СУБД;
  • Управляемые блокировки, реализуемые .

В подавляющем большинстве случаев уровень изоляции транзакций, который использует в СУБД, обеспечивает высокую параллельность работы пользователей и не требует от разработчика каких-либо дополнительных действий:

  • Microsoft SQL Server — Read Committed Snapshot;
  • PostgreSQL — Read Committed.

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

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

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

Когда устанавливать управляемые блокировки

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

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

Существует два режима управляемых блокировок: разделяемый и исключительный.

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

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

Типы встроенного языка

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

Для каждого возможного пространства блокировок в существуют собственные типы, связанные с элементами проекта:

Справочник
имя-справочника.Блокировки.Ссылка
имя-справочника.Блокировки.Код
Примечание: Этот тип существует, если у справочника есть реквизит Код.
имя-справочника.Блокировки.имя-дополнительного-пространства-блокировок
Примечание: Такой тип существует для каждого дополнительного пространства блокировок, описанного в справочнике.
Документ
имя-документа.Блокировки.Ссылка
имя-документа.Блокировки.Номер
Примечание: Этот тип существует, если у документа есть реквизит Номер.
имя-документа.Блокировки.имя-дополнительного-пространства-блокировок
Примечание: Такой тип существует для каждого дополнительного пространства блокировок, описанного в документе.
План обмена
имя-плана-обмена.Блокировки.Ссылка
имя-плана-обмена.Блокировки.имя-дополнительного-пространства-блокировок
Примечание: Такой тип существует для каждого дополнительного пространства блокировок, описанного в плане обмена.
Пользователи

Пользователи.Блокировки.Ссылка

Регистр сведений
имя-регистра-сведений.Блокировки.КлючЗаписи
имя-регистра-сведений.Блокировки.Измерения

Явная установка управляемых блокировок

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

Например, в следующем примере разделяемая блокировка устанавливается на элемент справочника Товары, ссылка на который сохранена в переменной СсылкаНаТовар.

пер Блокировка = новый Товары.Блокировки.Ссылка(
                     РежимБлокировки = РежимБлокировки.Разделяемый, 
                     Ссылка = СсылкаНаТовар
                 )
Блокировки.Заблокировать(Блокировка)

Если нужно установить исключительную блокировку, то режим можно не указывать, т.к. РежимБлокировки.Исключительный это его стандартное значение:

Блокировки.Заблокировать(новый Товары.Блокировки.Код(Код = "00001"))

Неявная установка управляемых блокировок

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

  • имя-справочника.Ссылка.ЗагрузитьОбъект();
  • Пользователи.ЗагрузитьОбъект();

Стандартно эти методы не устанавливают блокировки, но если в них передать параметр Истина, тогда блокировка будет установлена. Например, запись:

пер ЭлементСправочника = СсылкаНаТовар.ЗагрузитьОбъект(Истина)

установит следующую исключительную блокировку:

Блокировки.Заблокировать(новый Товары.Блокировки.Ссылка(Ссылка = СсылкаНаТовар))

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

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

Например, запись:

КурсыВалют.Заблокировать(Запись.КлючЗаписи)

установит следующую исключительную блокировку:

Блокировки.Заблокировать(новый КурсыВалют.Блокировки.КлючЗаписи(КлючЗаписи = Запись.КлючЗаписи))

Автоматическая установка управляемых блокировок

При записи данных методами встроенного языка (например имя-справочника.Записать()) или из интерфейса прикладного решения (например, нажатие Сохранить) автоматически устанавливает исключительные управляемые блокировки. Они полностью аналогичны тем блокировкам, которые вы могли бы установить самостоятельно.

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

Например, при выполнении:
пер ТоварыЭлемент = СылкаНаТовар.ЗагрузитьОбъект()
ТоварыЭлемент.Записать()
Будет автоматически установлена, в числе прочих, такая блокировка:
Блокировки.Заблокировать(новый Товары.Блокировки.Ссылка(СылкаНаТовар))