Почитать можно здесь: https://its.1c.ru/db/metod8dev#content:5839:hdoc
В свойствах конфигурации устанавливается режим управления блокировками:
- Автоматический - блокировка выполняется на уровне СУБД. Не всегда эффективна, так как для некоторых СУБД блокировка данных может выполнятся на уровне таблиц (Файловая система и PostgreeSQL)
- Управляемый - включается механизм блокировки 1С (собственный менеджер блокировок). В этом случае программист сам задает какие записи будут блокироваться и блокировка происходит на уровне записей (кроме файлового режима). Менеджер блокировок 1С не связан с блокировками СУБД - это собственный объект 1С.
- Автоматический и управляемый - режим блокировки будет определяться для каждого конкретного объекта (свойство регистра "Режим управления блокировкой данных"). Этот режим предназначен для перехода от автоматической блокировки к управляемой или чтобы повысить параллельность работы при проведении конкретного документа.
Если установлен смешанный режим, то надо учитывать, что одна транзакция может вызывать другую и надо учитывать совместимость режимов блокировок разных транзакций:
Режим существующей транзакции
|
Режим начинаемой транзакции
|
Результат
|
Автоматический
|
Автоматический
|
Начинаемая транзакция будет выполнена в автоматическом режиме
|
Управляемый
|
Управляемый
|
Начинаемая транзакция будет выполнена в управляемом режиме
|
Автоматический
|
Управляемый
|
Начинаемая транзакция будет выполнена в автоматическом режиме
|
Управляемый
|
Автоматический
|
Будет вызвана исключительная ситуация
|
Вызов блокировок:
- При вызове метода НачатьТранзакцию(<РежимБлокировок>) - по умолчанию РежимБлокировок = Автоматический.
- При интерактивной записи объекта (например документа)
- При проведении документа - блокировка набора записей регистров.
Установка управляемых блокировок
Класс БлокировкаДанных
Сначала создаем объект класса БлокировкаДанных
Блокировка = Новый БлокировкаДанных;
Потом добавляем в него элементы блокировки
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементБлокировка содержит:
- свойство «Режим» (исключительная по умолчанию)
- «Область» - в нашем случае это "РегистрНакопления.ТоварыНаСкладах"
- Источник – задаются специальными методами
- Поля - задаются специальными методами
Режим: Исключительный / Разделяемый
Совместимость операций при управляемой блокировке
|
Чтение
|
Разделяемая блокировка
|
Исключительная блокировка
|
Запись
|
Чтение |
+ |
+ |
+ |
+ |
Разделяемая блокировка |
+ |
+ |
- |
- |
Исключительная блокировка |
+ |
- |
- |
- |
Запись |
+ |
- |
- |
- |
Существует два способа задания условий на поля пространств блокировки:
- с помощью явного задания имени поля и его значения;
- с помощью указания источника данных, содержащего необходимые значения
Явное задание
При явном задании имени поля и его значения необходимо использовать метод УстановитьЗначение() объекта ЭлементБлокировкиДанных. Например:
// Создать объект блокировка данных
БлокировкаДанных = Новый БлокировкаДанных;
// Добавить новый элемент блокировки, блокирующий «нечто» в данных регистра накопления Остатки номенклатуры
ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрНакопления.ОстаткиНоменклатуры");
// Установить режим блокировки - исключительный. Другие транзакции, устанавливающие управляемые
// блокировки, не смогут даже начать чтение этих данных
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
// Указать, что именно мы блокируем в данных регистра Остатки номенклатуры - все «записи», у которых
// значение измерения Склад равно значению, содержащемуся в переменной Склад
ЭлементБлокировки.УстановитьЗначение("Склад", Склад);
Для значений типа Дата или Число в качестве значения может быть задан некоторый диапазон значений. Тогда установить значение можно следующим образом:
// Создать объект Диапазон, описывающих интервал от начала месяца, к которому принадлежит указанная дата,
// до указанной даты
Диапазон = Новый Диапазон(НачалоМесяца(Дата), Дата);
// Указать, что именно мы блокируем в данных регистра Продажи - все «записи», у которых
// значение измерения Контрагент равно значению, содержащемуся в переменной Контрагент,
// и значение поля Период содержится в указанном диапазоне
ЭлементБлокировки.УстановитьЗначение("Период", Диапазон);
С помощью источника данных
// Получим таблицу, в которой хранится список объектов для установки ограничений. В данном случае это таблица значений содержащая список номенклатуры.
//Надо позаботиться о том, чтобы не было дублированных строк в таблице источнике
ДанныеДляБлокировки = ПакетРезультатЗапроса[4];
БлокировкаДанных = Новый БлокировкаДанных;
//добавляем элемент блокировки
ЭлементБД = БлокировкаДанных.Добавить("РегистрНакопления.СтоимостьТоваров");
// Укажем источник данных как сформированный ранее список
ЭлементБД.ИсточникДанных = ДанныеДляБлокировки;
// укажем связь между измерением в регистре и именем колонки в таблице источника, в нашем случае имя измерения регистра и колонки в таблице совпадают и равны "Номенклатура"
ЭлементБД.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
// Блокируем
БлокировкаДанных.Заблокировать();
В этом примере будут заблокированы все записи в регистре накопления "СтоимостьТоваров" у которых значение измерения "Номенклатура" содержит какое-либо значение из таблицы ДанныеДляБлокировки.
Если надо установить блокировку по набору измерений, то добавляем условие блокировки в этот же элемент блокировки, например с помощью явного указания
ЭлементБД.УстановитьЗначение("Контрагент", НужныйКонтрагент);
В этом случае будут заблокированы все записи в регистре накопления, у которых измерение "Номенклатура" содержит значение из таблицы ДанныеДляБлокировки и измерение "Контрагент" равно заданному значению НужныйКонтрагент.
Установка блокировки на бухгалтерский регистр
Пример:
// Блокируем регистр Хозрасчетный для получения остатков
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрБухгалтерии.Хозрасчетный");
//устанавливаем ограничения на измерения регистра бухгалтерии
ЭлементБлокировки.УстановитьЗначение("Период", Новый Диапазон(, Реквизиты.Период)); //Есть мнение, что смысла в такой блокировке нет, поэтому на практике наверно можно не устанавливать.
ЭлементБлокировки.УстановитьЗначение("Организация", Реквизиты.Организация);
ЭлементБлокировки.УстановитьЗначение("Счет", Реквизиты.Счет);
//получаем список субконто по счету и устанавливаем ограничения на блокировку по таблице значений субконто
ТаблицаДоговоровПоСчету = ... //формируем таблицу значений с колонками "Контрагент,ДоговорКонтрагента". Строки не должны дублироваться.
ЭлементБлокировки.ИсточникДанных = ТаблицаДоговоровПоСчету;
ДанныеСчета = БухгалтерскийУчетВызовСервераПовтИсп.ПолучитьСвойстваСчета(Реквизиты.Счет);
Для НомерСубконто = 1 По ДанныеСчета.КоличествоСубконто Цикл
Если ДанныеСчета["ВидСубконто" + НомерСубконто] = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты Тогда
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты, "Контрагент");
ИначеЕсли ДанныеСчета["ВидСубконто" + НомерСубконто] = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры Тогда
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры, "ДоговорКонтрагента");
КонецЕсли;
КонецЦикла;
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
Установка блокировки на субконто
Если верить сайту Курсы-по-1с, то можно использовать разные способы установки блокировки по субконто:
- Установить по источнику (см. пример выше)
- Установить по наименованию поля "Субконто1". В этом случае блокировка установится только на те счета, у которых в Субконто1 будет выбранное значение. Остальные случаи игнорируются.
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(“Субконто1″,”Номенклатура”);
- Установить по типу субконто. В этом случае заблокированы будут все записи с значением субконто, независимо от его положения в аналитике. (этот вариант проверить не получилось, так как в отладке с свойствах блокировки запись не добавляется. Надо тестировать экспериментальным путем.)
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(ПланВидовХарактеристик.ВидыСубконто.Номенклатура, “Номенклатура”);
БлокироватьДляИзменения
Начиная с 1С 8.2 у набора записей регистров накопления и бухгалтерии появилось свойство «БлокироватьдляИзменения» (отрабатывается системой быстрее, чем БлокировкаДаных). Оно устанавливается перед методом «Записать». Это свойство имеет логический тип и может быть использовано при использовании подхода «Сначала запись, потом чтение» при проведении и контроле остатка. В случае, если сначала проверяем остатки, то надо ставить ручную блокировку.
Пример:
Движения.ТоварыНаСкладах.БлокироватьДляИзменения = Истина;
Свойство автоматически устанавливается в Ложь для всех регистров после успешной записи документа или при отменен транзакции.
При попытке использования в автоматическом режиме блокировки вызовет исключение.
ВАЖНО. Надо понимать, что БлокироватьДляИзменения не ставит блокировку, а отключает режим разделения итогов на момент записи движений. При записи набора записей регистра блокировка будет установлена в любом случае.
Если у регистра установлен режим разделения итогов и не поставили БлокироватьДляИзменения = Истина, то блокировка будет установлена на все измерения регистра плюс разделитель. Если кто-то будет делать в этот момент аналогичную операцию, то обе блокировки установятся корректно, так как в перечень полей блокировки включен разделитель. Если далее в алгоритме предусмотрен контроль остатков, то будет осуществлен запрос к этому регистру и тут оба пользователя получат взаимоблокировку, так как обе блокировки включают одинаковый набор измерений и данных (кроме разделителя).
Когда включаем БлокироватьДляИзменения = Истина, то из полей блокировки исключается разделитель, и второй пользователь не сможет установить свою блокировку, так как без разделителя набор полей будет одинаков.
Отсюда вывод: Если у регистра не установлено разделение итогов и нет контроля остатков после записи, то использовать БлокироватьДляИзменения бесполезно!
Ещё прикол: платформы 8.2 и 8.3 по разному обрабатывают БлокироватьДляИзменения.
В 8.3 СУБД может работать как версионник, т.е. одновременно модифицировать одни и те же записи, создавая при этом разные версии одной записи. В режиме совместимости 8.2 такой проблемы нет.
Использование БлокироватьДляИзменения на платформе 8.3 переводит блокировку на сторону 1С Сервера (механизм управляемых блокировок), т.е. до обработки СУБД, что снимает проблему одновременной записи.
Из этого следует, что использовать БлокироватьДляИзменения надо если:
- нужен контроль остатков
- контроль остатков выполняется после записи
- у регистра включен режим разделения итогов
- используются управляемые блокировки
Автоматический режим блокировки
Для автоматических блокировок исключительные блокировки устанавливаются на уровне конструктора запросов (вкладка «Дополнительно», галка «Блокировать получаемые данные для последующего изменения»). В этом случае блокировка будет установлена на записи, выбираемые в запросе. В тексте запроса появиться секция «ДЛЯ ИЗМЕНЕНИЯ».
Статьи по блокировкам:
На сайте Гилева - рассмотрен пример контроля остатков с применением блокировок и без них.
То же сайт Гилева. Разбор свойства БлокироватьДляИзменения набора записей регистра.
На сайте Чистова с разбором методики оперативного проведения
|