1с поля блокировки данных. Перевод конфигурации на управляемые блокировки

Для внедренцев, которые работают с типовыми или собственными конфигурациями – и тех, кто готовится к Аттестации на 1С:Специалист по платформе.

В статье мы разберем:

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

Время на прочтение – 20 минут.

Итак, две методики контроля остатков в 1С:Предприятии 8.3

Давайте начнем с того, что обозначения “старая методика” и “новая методика” достаточно условны. В самом деле, если “новая методика” используется с 2010 года – она уже не очень новая:)

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

“Старая методика” – это подход к контролю остатков, который использовался со времен «1С:Предприятие 8.0».

C 2010 года, с развитием платформы и добавлением новых возможностей с «1С:Предприятие 8.2» – применяется “новая методика” (однако – не везде ).

В чем разница?

Принципиальная разница – в моменте контроля остатков:

  • В “старой” методике остатки контролируются ДО записи движений в регистры.
    Сначала проверяем остатки, если остатков “не хватает” (будут возникать отрицательные остатки) – проводить документ не будем
  • В “новой” методике – контроль происходит ПОСЛЕ записи движений, то есть постфактум.
    Если после проведения образовались отрицательные остатки – нужно «откатить» транзакцию, то есть отменить проведение документа.

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

Ok, значит, старая методика ушла в прошлое и это удел УТ 10.3?

Нет, это не совсем так.

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

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

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

Например, вот так:

Однако встречаются конфигурации, где и количество, и стоимость учитываются на одном регистре. И вот здесь-то обоснованно остается работать старая методика контроля остатков !

Вот пример одного регистра и для количества, и для себестоимости:

А что насчет типовых конфигураций? Там ведь только новая методика, верно?

Не всегда!

Вот, например, в «1C:Управление торговлей 11.3» есть 2 регистра:

При проведении документов отгрузки регистр «Себестоимость товаров» не заполняется вообще. Данные в этот регистр попадают только при выполнении регламентных операций по закрытию месяца.

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

Что касается «1C:Бухгалтерии», то там и количество, и себестоимость хранятся в одном регистре бухгалтерии, на соответствующих счетах БУ.

Поэтому в БП 3.0 используется старая методика .

Обратите внимание, что количественный и стоимостной учет в УТ 11 ведутся с разной аналитикой. Например, себестоимость дополнительно ведется в разрезе организации, подразделения, менеджера, виды деятельности НДС и так далее.

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

Про оперативное проведение документов

В этом простом вопросе часто встречаются заблуждения.

Иногда считают, что оперативное проведение – это контроль остатков по новой методике. Это не так, от слова «совсем».

Оперативное проведение можно анализировать при контроле остатков, но не обязательно.

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

Настраивается оно с помощью специального свойства документа:

Что значит «регистрировать здесь и сейчас»? Платформа для оперативно проводимых документов выполняет ряд действий:

  • Документам, проводимым сегодня, присваивается текущее время
  • Если два документа проводятся одновременно, каждый будет иметь свое время (то есть система разнесет документы по разным секундам)
  • Документы нельзя будет провести будущей датой.

Но главное другое – система передает признак оперативности проведения документа в обработку проведения:

Для оперативно проводимых документов можно не указывать параметр в запросе, будут получаться актуальные остатки на 31.12.3999 год:

Актуальные остатки хранятся в системе и получаются максимально быстро (остатки на другие даты в большинстве случаев получаются расчетным путем).

Таким образом оперативное проведение можно принять и для старой, и для новой методики контроля остатков .

Интересный факт.

В УТ 11 документам, списывающим номенклатуру, запрещено проводиться оперативно. Например, это документы «Реализация товаров и услуг», «Сборка товаров», «Перемещение товаров», «Внутреннее потребление товаров» и другие.

Почему так сделано?

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

Контроль остатков по новой методике – без блокировок

Коротко рассмотрим алгоритм контроля остатков при проведении документа «Реализация товаров и услуг» на модельной конфигурации.

Есть два регистра:

  • Свободные остатки – для количественного учета
  • Себестоимость товаров – для учета себестоимости

Для контроля остатков товаров достаточно работы с регистром «Свободные остатки».

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

Запрос = Новый Запрос;


#Область Область1
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
#КонецОбласти


#Область Область2
Запрос.Текст =
"ВЫБРАТЬ

|ПОМЕСТИТЬ ТоварыДокумента
|ИЗ
|ГДЕ
|
|СГРУППИРОВАТЬ ПО
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;

|ВЫБРАТЬ
| &Дата КАК Период,
| ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход) КАК ВидДвижения,
| ТоварыДокумента.Количество КАК Количество
|ИЗ
";
Запрос.УстановитьПараметр("Дата", Дата);
#КонецОбласти

// 4. Запись движений в БД
#Область Область4
Движения.Записать();
#КонецОбласти


#Область Область5
Запрос.Текст =
"ВЫБРАТЬ
| -СвободныеОстаткиОстатки.КоличествоОстаток КАК Дефицит
|ИЗ
| ТоварыДокумента КАК ТоварыДокумента
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.СвободныеОстатки.Остатки(
| &МоментВремени,
| Номенклатура В
| (ВЫБРАТЬ
| ТоварыДокумента.Номенклатура КАК Номенклатура
| ИЗ
| ТоварыДокумента КАК ТоварыДокумента)) КАК СвободныеОстаткиОстатки
| ПО ТоварыДокумента.Номенклатура = СвободныеОстаткиОстатки.Номенклатура
|ГДЕ
| СвободныеОстаткиОстатки.КоличествоОстаток < 0";
#КонецОбласти


#Область Область6
МоментКонтроляОстатков =
?(Режим = РежимПроведенияДокумента.Оперативный,
Неопределено,
Новый Граница(МоментВремени(), ВидГраницы.Включая));
Запрос.УстановитьПараметр("МоментВремени", МоментКонтроляОстатков);
РезультатЗапроса = Запрос.Выполнить();
#КонецОбласти


#Область Область7
Если НЕ РезультатЗапроса.Пустой() Тогда
Отказ = Истина;
ВыборкаОшибки = РезультатЗапроса.Выбрать();
Пока ВыборкаОшибки.Следующий() Цикл
Сообщение.Текст = "Недостаточно товара в количестве: "+ВыборкаОшибки.Дефицит;
Сообщение.Поле = "Товары["+(ВыборкаОшибки.НомерСтроки-1)+"].Количество";
Сообщение.Сообщить();
КонецЦикла;
КонецЕсли;
#КонецОбласти


#Область Область8
Если Отказ Тогда
Возврат;
КонецЕсли;
#КонецОбласти

КонецПроцедуры

Рассмотрим ключевые точки алгоритма контроля остатков.

1. Инициализация менеджера временных таблиц

Менеджер будет необходим, чтобы созданная в запросе временная таблица была доступна и в следующих запросах.

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

2. Запрос, группирующий данные табличной части

В запросе выбираются сгруппированные данные табличной части.

Обратите внимание, что выбирается и номер строки документа – он потребуется для контекстной привязки сообщения об ошибке. Для номера строки используется агрегатная функция МИНИМУМ() – то есть сообщение будет привязано к первой строке, где встречается указанная номенклатура.

В первом запросе пакета создается временная таблица. Во втором запросе выбираются данные временной таблицы и добавляются 2 поля, необходимые для каждой записи регистра – Период и ВидДвижения.

Плюсы такого подхода:

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

Кстати, подобный подход используется в типовых конфигурациях, в частности, в УТ 11 и БП 3.0.

4. Запись движений в БД

Запись можно было бы выполнить одной командой (вместо двух) – Движения.СвободныеОстатки.Записать().

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

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

  • Вначале установить флаг Записывать у необходимых наборов записей регистров
  • Затем вызывать метод Записать() коллекции Движения, который записывает в БД все наборы с установленным флагом Записывать

После выполнения команды «Движения.Записать()» флаг Записывать у всех наборов сбросится в Ложь.

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

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

Метод Записать() коллекции Движения записывает наборы записей в одинаковой последовательности даже для разных документов.

Запись же движений вручную может привести к проблемам.

Приведем пример.

Если в документе «Реализация» выполнить запись так:

Движения.СвободныеОстатки.Записать();
...
Движения.СебестоимостьТоваров.Записать();

А в документе «Перемещение товаров» изменить порядок:

Движения. СебестоимостьТоваров.Записать();
...
Движения. СвободныеОстатки.Записать();

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

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

5. Запрос, получающий отрицательные остатки

В запросе выбираются отрицательные остатки по номенклатуре из документа.

Отрицательный остаток – это и есть нехватка (дефицит) товара.

Соединение с товарами из документа выполняется только для получения номера строки.

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

6. Определение момента времени для контроля остатков

Вот здесь нам пригодилось оперативное проведение.

Если документ проводится оперативно, то момент для получения остатков – Неопределено, что означает получение актуальных остатков.

Если это неоперативное проведение, то мы получаем момент времени «после» документа – чтобы учесть только что сделанные движения.

Напомним, что получение актуальных остатков – быстрая операция по сравнению с получением остатков на произвольным момент времени.

Именно в этом и заключается выигрыш оперативно проводимых документов.

7. Если запрос не пустой, значит, образовались отрицательные остатки

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

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

8. Если есть ошибки, то возвращаемся из обработчика события

Если была хоть одна ошибка – выходим из процедуры.

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

Реализация списания себестоимости по партиям

После того, как проверка остатков прошла успешно, можно приступать к списанию партий.

Код для списания по FIFO будет таким:

// I. Анализ смещения даты документа вперед


И НЕ ЭтотОбъект.ЭтоНовый()
И ЭтотОбъект.Проведен Тогда

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Документ.Дата КАК Дата
|ИЗ
|ГДЕ

РезультатЗапроса = Запрос.Выполнить();
ВыборкаДокумент.Следующий();

Иначе
Ложь);
КонецЕсли;

КонецПроцедуры

Процедура ПриЗаписи(Отказ)

ЭтотОбъект.ДополнительныеСвойства.Вставить("ДатаДокументаСдвинутаВперед",
ЭтотОбъект.Дата>


КонецЕсли;

КонецПроцедуры

Процедура ОбработкаПроведения(Отказ, Режим)

Запрос = Новый Запрос;

// 1. Инициализация менеджера временных таблиц
#Область Область1
...
#КонецОбласти

// 2. Запрос, группирующий данные табличной части
#Область Область2
...
#КонецОбласти

// 4. Запись движений в БД
#Область Область4
...
#КонецОбласти

// 5. Запрос, получающий отрицательные остатки
#Область Область5
...
#КонецОбласти

// 6. Определение момента времени для контроля остатков
#Область Область6
...
#КонецОбласти

// 7. Если запрос не пустой, значит образовались отрицательные остатки
#Область Область7
...
#КонецОбласти

// 8. Если есть ошибки, то возвращаемся из обработчика события
#Область Область8
...
#КонецОбласти

// II. Подготовка наборов записей регистра "Себестоимость товаров"
#Область ОбластьII

Движения.Записать();
КонецЕсли;
Движения.СебестоимостьТоваров.Записывать = Истина;
#КонецОбласти

// III. Запрос получающий остатки партий для списания по FIFO
#Область ОбластьIII
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыДокумента.Номенклатура КАК Номенклатура,
| ТоварыДокумента.НомерСтроки КАК НомерСтроки,

| Остатки.Партия КАК Партия
|ИЗ
| ТоварыДокумента КАК ТоварыДокумента
| &МоментВремени,
| Номенклатура В
| (ВЫБРАТЬ
| ИЗ

|УПОРЯДОЧИТЬ ПО
|ИТОГИ
| МАКСИМУМ(Количество),
| СУММА(КоличествоОстаток)
|ПО
| Номенклатура";
РезультатЗапроса = Запрос.Выполнить();
#КонецОбласти

// IV. Цикл по номенклатуре документа
#Область ОбластьIV

// V. Получим количество для списания
// VI. Цикл по партиям по FIFO
Пока ВыборкаПартии.Следующий() И ОсталосьСписать>0 Цикл
// VII. Проверка на нулевой остаток
Если ВыборкаПартии.КоличествоОстаток=0 Тогда
Продолжить;
КонецЕсли;
Движение.Период = Дата;

// VIII. Расчет количества и суммы для списания

// IX. Уменьшим количество для списания
КонецЦикла;
КонецЦикла;
#КонецОбласти

КонецПроцедуры

Разберем ключевые точки алгоритма списания партий по FIFO.

I. Анализ смещения даты документа вперед

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

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

  • Перед записью – для получения старой даты документа и проверки режима проведения документа
  • При записи – для получения новой даты документа

Данные между событиями передаем через специальную коллекцию объекта – «ДополнительныеСвойства». Она существует пока текущая версия объекта находится в памяти, то есть доступна для всех событий при проведении.

Похожий прием используется в типовой «1С:Бухгалтерии 8». Но там используется одно событие «Перед записью».

Почему в БП не нужно задействовать «При записи»?

Всё просто – документы отгрузки в бухгалтерии не могут проводиться оперативно. А это значит, что время документа не будет принимать оперативную отметку (если документ перепроводится текущим днем), поэтому и старую и новую дату документа можно получить в событии «Перед записью».

II. Подготовка наборов записей регистра «Себестоимость товаров»

Для документа установлен режим удаления движений – “При отмене проведения”:

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

Приведем пример:

  • Остаток мониторов LG на момент проведения документов – 10 шт.
  • Проводится документ, который списывает 8 шт.
  • В этом же документе время увеличивается на 1 минуту, перепроводим

Если не будет удаления старых движений, то система сообщит о нехватке 6 мониторов, поскольку текущие движения документа уже списали 8 из 10 имеющихся мониторов.

Примечание. Иногда встречается совет – удалять движения только при оперативном проведении.

Но это неправильно: ситуации изменения «неоперативных» документов (вчерашних и более ранних) они не учтут.

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

III. Запрос, получающий остатки партий для списания по FIFO

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

На уровне итогов получается количество из документа – МАКСИМУМ(Количество) и остаток партии – СУММА(КоличествоОстаток).

Как Вы думаете, может ли количество из документа превышать суммарный остаток номенклатуры по всем партиям?

Если движения по регистрам “СвободныеОстатки” и “СебестоимостьТоваров” по количеству делаются синхронно (и приход, и расход), то такой ситуации возникнуть не может. На это мы и будем закладываться при списании партий.

IV. Цикл по номенклатуре документа

Благодаря итогам в запросе во внешнем цикле обходим номенклатуру из документа.

V. Получим количество для списания

Запомним, какое количество нужно списать. Далее это количество будет уменьшаться.

VI. Цикл по партиям по FIFO

Вложенный цикл будет содержать партии по текущей номенклатуре.

VII. Проверка на нулевой остаток

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

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

VIII. Расчет количества и суммы для списания

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

Сумма рассчитывается элементарной пропорцией.

Если списывается весь остаток партии, то будет списана и вся сумма этой партии. Это математика 3-го класса церковно-приходской школы: Х*Y/X = Y:)

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

А тем, кто дает вредные советы имеет смысл заглянуть в конфигурацию «1С:Бухгалтерия 8». Там (о, ужас!) нет проверки на то, что списывается партия целиком:)

Вот скрин общего модуля «Учет товаров», метод «СписатьОстаткиТоваров»:

IX. Уменьшим количество для списания

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

Зачем нужны управляемые блокировки?

Вот мы и дошли до управляемых блокировок.

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

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

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

В этом примере два пользователя почти одновременно проводят продажу товаров – документ №2 начал проводиться чуть позже документа 1.

При получении остатка система сообщает, что остаток 10 шт., и оба документа успешно проводятся. Печальный итог – на складе минус 5 мониторов LG.

Но при этом контроль остатков работает! То есть, если документ №2 будет проводиться после окончания проведения документа №1, система не проведет документ №2:

Иногда встречается заблуждение – «У меня в базе одновременно работают только 3-4 пользователя, вероятность параллельного проведения документов равна нулю, поэтому на блокировки можно не отвлекаться».

Это очень опасное рассуждение .

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

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

Как решить проблему при параллельном проведении документов?

Решение простое – заблокировать мониторы LG в момент времени Т1, так чтобы другие транзакции не могли обратиться к остаткам по этому товару.

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

Буквально пару слов о классификации блокировок.

Существует 2 типа блокировок:

  • Объектные
  • Транзакционные .

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

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

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

Когда нужно накладывать блокировки?

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

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

То есть блокировки нужно накладывать при проведении всех документов?

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

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

В примере выше таким ресурсом является остаток по товару. Система должна была заблокировать остаток с момента получения данных об остатке (Т1) до окончания транзакции (Т3).

Примечание. Транзакция при проведении документа №1 начинается раньше, чем момент получения остатков. Но для простоты считаем, что Т1 – и время начала проведения документа, и момент получения остатков.

Пример, когда не нужно накладывать блокировку – проведение документа «Поступление товаров». В этом случае нет никакой конкуренции за ресурсы (остатки, …), поэтому блокировка будет вредна: она уменьшит масштабируемость системы.

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

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

Вместо теории можем привести пруф – все современные типовые конфигурации работают на управляемых блокировках.

Поэтому в нашей модельной конфигурации будет выбран соответствующий режим:

Управляемые блокировки в новой технологии контроля остатков

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

Причем правильный вариант наложения блокировки – как можно позднее.

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

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

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

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

// 3.1. Блокировка остатков регистра
#Область Область3_1
Движения.СвободныеОстатки.БлокироватьДляИзменения = Истина;
#КонецОбласти

// 4. Запись движений в БД
#Область Область4
Движения.СвободныеОстатки.Записывать = Истина;
Движения.Записать();
#КонецОбласти
...

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

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

Но для нашей статье принципиально следующее – система установит блокировку на комбинацию записываемых в регистр данных. А детально работу свойства БлокироватьДляИзменения мы рассмотрим в отдельной статье.

Кстати, в типовой УТ 11 не так-то просто найти установку свойства БлокироватьДляИзменения для регистра “Свободные остатки”. Дело в том, что это выполняется в модуле набора записей регистра, в событии “Перед записью”.

Вот и всё, одной строкой кода была обеспечена корректная работа системы!

Важно . Мы не накладываем блокировку на регистр “Себестоимость товаров”.

Почему? Такая блокировка являлась бы излишней (а это определенная нагрузка на сервер 1С), поскольку движения в регистры “Свободные остатки” и “Себестоимость товаров” выполняются всегда синхронно, то есть последовательно друг за другом.

Поэтому, заблокировав товары из “Свободных остатков”, мы не допустим другие транзакции до этих товаров и в регистре “Себестоимость товаров”.

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

Старая методика контроля остатков

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

Пусть это будет регистр “Себестоимость товаров”:

Тогда алгоритм проведения документа “Реализация товаров” будет выглядеть вот так:

// 1. Обработчик события "Перед записью"
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

Если РежимЗаписи = РежимЗаписиДокумента.Проведение
И НЕ ЭтотОбъект.ЭтоНовый()
И ЭтотОбъект.Проведен Тогда

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Документ.Дата КАК Дата
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документ
|ГДЕ
| Документ.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ЭтотОбъект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДокумент = РезультатЗапроса.Выбрать();
ВыборкаДокумент.Следующий();

ЭтотОбъект.ДополнительныеСвойства.Вставить("СтараяДатаДокумента", ВыборкаДокумент.Дата);

Иначе
КонецЕсли;

КонецПроцедуры

Процедура ПриЗаписи(Отказ)

Если НЕ ЭтотОбъект.ДополнительныеСвойства.Свойство("ДатаДокументаСдвинутаВперед") Тогда

ЭтотОбъект.ДополнительныеСвойства.Вставить("ДатаДокументаСдвинутаВперед",
ЭтотОбъект.Дата>ЭтотОбъект.ДополнительныеСвойства.СтараяДатаДокумента);

Сообщить(ЭтотОбъект.ДополнительныеСвойства.ДатаДокументаСдвинутаВперед);
КонецЕсли;

КонецПроцедуры

Процедура ОбработкаПроведения(Отказ, Режим)

// 2. Удаление "старых" движений документа
Если ДополнительныеСвойства.ДатаДокументаСдвинутаВперед Тогда
Движения.СебестоимостьТоваров.Записывать = Истина;
Движения.СебестоимостьТоваров.Очистить();
Движения.Записать();
КонецЕсли;

// 3. Установка флага для записи движений в конце транзакции
Движения.СебестоимостьТоваров.Записывать = Истина;

// 4. Запрос, получающий остатки по партиям на момент времени документа
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТовары.Номенклатура КАК Номенклатура,
| СУММА(РеализацияТовары.Количество) КАК Количество,
| МИНИМУМ(РеализацияТовары.НомерСтроки) КАК НомерСтроки
|ПОМЕСТИТЬ ТоварыДокумента
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
|ГДЕ
| РеализацияТовары.Ссылка = &Ссылка
|СГРУППИРОВАТЬ ПО
| РеализацияТовары.Номенклатура
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ТоварыДокумента.Номенклатура КАК Номенклатура,
| ТоварыДокумента.Количество КАК Количество,
| ТоварыДокумента.НомерСтроки КАК НомерСтроки,
| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
| ЕСТЬNULL(Остатки.СуммаОстаток, 0) КАК СуммаОстаток,
| Остатки.Партия КАК Партия
|ИЗ
| ТоварыДокумента КАК ТоварыДокумента
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СебестоимостьТоваров.Остатки(
| &МоментВремени,
| Номенклатура В
| (ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура
| ИЗ
| ТоварыДокумента КАК Т)) КАК Остатки
| ПО ТоварыДокумента.Номенклатура = Остатки.Номенклатура
|УПОРЯДОЧИТЬ ПО
| Остатки.Партия.МоментВремени
|ИТОГИ
| МАКСИМУМ(Количество),
| СУММА(КоличествоОстаток)
|ПО
| НомерСтроки";

Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
Запрос.УстановитьПараметр("Ссылка", Ссылка);

РезультатЗапроса = Запрос.Выполнить();

ВыборкаНоменклатура = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

// 5. Цикл по номенклатуре - проверяем достаточность количества для списания
Пока ВыборкаНоменклатура.Следующий() Цикл

ДефицитНоменклатуры = ВыборкаНоменклатура.Количество - ВыборкаНоменклатура.КоличествоОстаток;

Если ДефицитНоменклатуры>0 Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Недостаточно товара в количестве: "+ДефицитНоменклатуры;
Сообщение.Поле = "Товары["+(ВыборкаНоменклатура.НомерСтроки-1)+"].Количество";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;

Если Отказ Тогда
Продолжить;
КонецЕсли;

// 6. Получим количество для списания
ОсталосьСписать = ВыборкаНоменклатура.Количество;
ВыборкаПартии = ВыборкаНоменклатура.Выбрать();

// 7. Цикл по партиям
Пока ВыборкаПартии.Следующий() И ОсталосьСписать>0 Цикл

Движение = Движения.СебестоимостьТоваров.ДобавитьРасход();
Движение.Период = Дата;
Движение.Номенклатура = ВыборкаПартии.Номенклатура;
Движение.Партия = ВыборкаПартии.Партия;
// 9. Расчет количества для списания
Движение.Количество = Мин(ОсталосьСписать, ВыборкаПартии.КоличествоОстаток);
// 10. Расчет суммы списания
Движение.Сумма = Движение.Количество*
ВыборкаПартии.СуммаОстаток/ВыборкаПартии.КоличествоОстаток;

// 11. Уменьшим количество для списания
ОсталосьСписать = ОсталосьСписать - Движение.Количество;

КонецЦикла;
КонецЦикла;

Вы попали на нужную страницу! Скорее всего, утром вы обнаружили, что любимая 1С 8.3 не запускается с сообщением: «Начало сеанса с информационной базой запрещено. Для выполнения резервного копирования… ».

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

Мой опыт подсказывает, что вы – пользователь (не системный администратор и не программист), а ваша информационная база – файловая (если база SQL, вашей проблемой уже занимаются специалисты). Для начала надо понять, в какой папке (каталоге) она расположена и удалить в этой папке один файл - 1Cv8.cdn (файл можно не сохранять, он больше не понадобится).

*Если вы ИТ-специалист, можете смело переходить к чтению раздела «Блокировка и снятие блокировки с информационной базы 1С».

В окне со списком информационных баз найдите свою базу (цифра 1 на иллюстрации ниже) и нажмите на нее один (и только один!) раз мышкой. Затем нажмите кнопку «Изменить» (цифра 2).

В списке может быть только одна база, поэтому это окно вам может быть знакомо как «окно запуска 1С». В этом случае просто нажмите кнопку «Изменить».

Если вы видите, что информационная база расположена на данном компьютере или в локальной сети - мой опыт не подвел – база файловая, и мы все делаем правильно. Скопируйте этот путь (цифры 3 и 4 ).

Теперь зайдите в эту папку.

На всякий случай, вот несколько вариантов запуска Проводника:

  • У вас Windows XP или Windows 7. Нажмите Пуск, Выполнить, вставьте ранее скопированное расположение информационной базы. Откроется Проводник.
  • У вас Windows 7. Но пункта «Выполнить» нет. Вставляйте расположение сразу после нажатия Пуск. Откроется Проводник.
  • У вас Windows 8 или Windows 10. Нажмите Пуск, в правом верхнем углу нажмите на Лупу, вставьте ранее скопированное расположение информационной базы, нажмите Enter. Откроется Проводник.

  • Найдите на панели задач желтую дискету и нажмите на нее. Вставьте расположение информационной базы в адресную строку в верхней части окна Проводника. (Правой кнопкой мыши на адресную строку, Изменить адрес, правой кнопкой еще раз на адресную строку, Вставить).

  • Универсальный способ для всех версий Windows и ее настроек. Нажмите на клавиатуре кнопку с флажком и, не отпуская ее, нажмите на клавиатуре латинскую R (или русскую К). Откроется окно «Выполнить», вставьте туда ранее скопированное расположение информационной базы и нажмите ОК.

Воспользовавшись одним из предложенных вариантов, вы попадете в окно проводника с расположением информационной базы.


В окне проводника найдите в списке файлов файл 1Cv8.cdn, нажмите на нем правой кнопкой мыши, выберите «Удалить», как показано на предыдущем рисунке.

Готово! Ваша «1С:Бухгалтерия» или «1С:Зарплата и управление персоналом» или «1С:Управление торговлей» снова запускаются.

Блокировка и снятие блокировки с информационной базы 1С. Разрушаем мифы.

В данном разделе вы найдете уникальную информацию по работе с блокировками, а также получите опровержение распространенных заблуждений на тему «Блокировка данных».

Как установить блокировку?

Механизм блокировки информационной базы предназначен для завершения текущих открытых сеансов и предотвращения новых подключений. Расположение функционала блокировки в меню может различаться в зависимости от конфигурации. Например, в УТ, редакция 11 (11.3.3.163) это НСИ и администрирование, [Сервис] Блокировка работы пользователей. Альтернативный вариант: НСИ и администрирование, Поддержка и обслуживание, Блокировка работы пользователей. В УТ, редакция 10.3 (10.3.21.2) это Сервис, Пользователи, Блокировка установки соединений с информационной базой.

*Существуют специальные отраслевые конфигурации, в которых блокировка с точки зрения интерфейса и с точки зрения механизма будет выглядеть не так, как описано в данной статье. Поскольку мы рассматриваем стандартный механизм для большинства конфигураций 1С, специальные отраслевые конфигурации затрагивать не будем.


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


Поскольку вводится начало и окончание действия блокировки, необходимо быть крайне внимательным в этом диалоге и ввести информацию в явном виде. Если бы в диалоге была бы возможность ввести начало блокировки «через 15 минут» длительностью «на 20 минут», или хотя бы справочно отображались эти величины на основании абсолютного времени начала и окончания блокировки, то было бы сложно установить блокировку длительностью в год, как это может случиться при ошибке ввода даты-времени.

Параметр «Время начала» рекомендуется установить как текущая дата/время + время, необходимое пользователям на подготовку к выходу с сохранением редактируемых документов. Например, сейчас 9 ч 50 мин, даем 10 минут пользователям для сохранения их результатов. Итого время начала блокировки должно быть 10 ч 00 мин.

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

Код для разблокировки – однократный «пароль» на запуск «с нуля», вопреки установленной блокировке, который может понадобиться в некоторых случаях (будет сказано далее). Вводить и запоминать обязательно. Этот параметр в случае SQL-варианта информационной базы виден в оснастке «Администрирование серверов 1С предприятия» и называется там «Код разрешения».

В случае SQL-варианта информационной базы дополнительно потребуется авторизация администратора информационной базы или администратора кластера.


Итак, после нажатия кнопки «Установить блокировку» и положительного ответа на подтверждение…


…вы вернетесь в предыдущее диалоговое окно, внешний вид которого изменился:


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


Запланирована? Быть может это как-то связано с регламентными заданиями?

Сработает ли запланированная блокировка работы пользователей, если установлена блокировка регламентных заданий? Да, сработает. Механизм блокировки не использует регламентные задания.

Что увидят пользователи и я сам?

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


Инициатор блокировки получает другое сообщение:


После начала действия блокировки в информационную базу нельзя будет зайти обычным способом. О том, как все-таки зайти, будет рассказано ниже. Обратите внимание, что диалог не содержит автоматического указания на время завершения блокировки, поэтому задача проинформировать пользователей о времени возобновления работы ложится на Администратора. Эту информацию можно указать в сообщении пользователю.



Бомба взрывается точно в назначенное время. Сирена воет до взрыва.

Вопреки распространенному мнению, что завершение сеансов активных пользователей производится мягко, после предупреждения, которое можно игнорировать и продолжить работу, на самом деле завершение, а лучше сказать, «обрубание», активных сеансов происходит точно по расписанию, жестко и с потерей всех несохраненных результатов. Все предупреждения выдаются в интервале от времени нажатия кнопки «Установить блокировку» до времени начала блокировки, после наступления которого, завершение активного сеанса произойдет без какого-либо уведомления, а 1С перейдет в цикл попыток запуска конфигурации заново, с интервалом в 1 минуту.

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

*Завершение сеансов пользователей в старых конфигурациях происходит чуть позже назначенного времени, т.к. пользователи сначала получают оповещение «Работа системы завершается».

А точно взорвется?

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

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


В журнале регистрации появится сообщение о runtime-ошибке, которое следует интерпретировать не как runtime-ошибку, а как «не все пользователи завершили свои сеансы»:


И это не единственная причина, по которой блокировка может не сработать (cм. далее разделы «По чьим часам?» и «А как же мои пользователи во Владивостоке?»).

Модальный диалог в SQL-варианте информационной базы на управляемых формах

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



Модальный диалог в SQL-варианте информационной базы на обычных формах

Сеансы пользователей завершаются.

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



Сработает ли блокировка, если установить блокировку и закрыть диалог?

Сработает ли блокировка, если установить блокировку и сразу выйти из 1С (т.е. завершить сеанс 1С до начала действия блокировки)?

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

По чьим часам сработает блокировка, если время на компьютерах немного отличается?

Проблема рассинхронизации часов

При файловой ИБ каждый компьютер сам проверяет, имеется ли в ИБ установленный временной диапазон блокировки, и сравнивает его со своими локальными часами. От точности своих часов зависит, сможет ли данный компьютер осуществить завершение сеанса точно в нужное время. Если база блокируется с 10:00, для одного компьютера этот момент наступит раньше, а для другого – позже.

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

Кажется, что речь может идти о секундах, в крайнем случае, минутах. Но на самом деле, на компьютере может быть, например, не установлено обновление операционной системы, поддерживающее переход на сезонное (зимнее/летнее) время, и ошибка уже может составлять не секунды, а часы. Легко провести такой эксперимент: запланируйте блокировку на 10 утра длительностью полчаса, а на одном из компьютеров переведите время на час вперед – блокировка на него не подействует.

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

А как же мои пользователи во Владивостоке?

Проблема абсолютного времени при пользователях из разных часовых поясов

Временной диапазон блокировки сохраняется в информационной базе. Посмотрите на содержимое блокировочного файла 1Cv8.cdn (который создается в файловом варианте ИБ), в нем записано время начала блокировки 17.07.2017 13:59 в формате ГГГГММДДЧЧММСС без какого-либо указания на часовой пояс:


Без указания на часовой пояс было бы понятно, о каком абсолютном времени идет речь, если время всегда относилось бы к какому-то конкретному часовому поясу, например UTC+0. Но в базе сохраняется локальное время по часам компьютера, который являлся инициатором блокировки. Из какого часового пояса был этот компьютер – неизвестно, а значит неизвестно абсолютное время блокировки.

Если в Москве, в централизованной ИБ, вы устанавливаете блокировку в 13:59, и этот момент времени для московских пользователей находится в будущем, то у пользователей этой же ИБ во Владивостоке 13:59 было 7 часов назад. И в зависимости от технического решения, в соответствии с которым осуществляется работа с ИБ пользователей Владивостока, блокировка этих пользователей либо сработает, либо нет.

Какие могут быть технические решения, в которых блокировка будет работать неправильно для пользователей Владивостока? Те, при которых клиентская часть 1С получит время по Владивостоку, а не по Москве. Например, офисы связаны в локальную сеть по VPN, а клиентская часть 1С запускается с локального компьютера, имея время UTC+10. Но если они работают с базой через RDP-соединение или в режиме RemoteApp на московском сервере, запуская на этом сервере клиентскую часть 1С – все будет хорошо, т.к. она будет иметь время UTC+3.

Имеется ли проблемы рассинхронизации часов и часового пояса в случае SQL-варианта информационной базы?

Нет. В данном варианте есть «часы сервера», которые принимаются за эталон.

Выкинет ли меня из Конфигуратора, если я был в нем, а блокировка начала действовать?

Можно ли будет зайти в Конфигуратор после начала действия блокировки?

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

Как снять блокировку?

В том же диалоге, в котором блокировка устанавливалась. Напоминаем, что после установки блокировки в нем вместо кнопки «Установить блокировку» кнопка «Снять блокировку».

В случае SQL-варианта ИБ снятие блокировки возможно также в оснастке «Администрирование серверов предприятия 1С». (см. далее)

Для чего нужен код разблокировки?

Для входа в ИБ в тот момент, когда действует блокировка. Ситуации, в которых это необходимо:

  • После установки блокировки был завершен сеанс работы с ИБ (вручную или в результате действия блокировки на самого инициатора), и требуется начать новый сеанс;
  • Время окончания блокировки по ошибке было не заполнено вообще;
  • Время окончания блокировки было заполнено ошибочно (например, был нечаянно введен следующий месяц или год);
  • Информационная база в SQL-варианте, и для отмены неверно установленной блокировки невозможно удалить файл 1Cv8.cdn в каталоге информационной базы.

В таком случае воспользуйтесь подсказкой, которая дается при запуске. Т.е. в окне со списком информационных баз нажмите «Изменить» и введите в дополнительные параметры запуска строку:

ENTERPRISE /F"Z:\Обмен\УТ 11" /CРазрешитьРаботуПользователей /UC12345

… с учетом каталога расположения и кода разблокировки.


Данную строку лучше скопировать в буфер обмена и подправить в диалоге «Редактирование информационной базы». Если вы перепутали тип кавычек или русскую «С» и латинскую, то увидите сообщение об ошибке:



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

Что делать, если я не устанавливал блокировку, а SQL-база кем-то заблокирована? При этом я не знаю код разблокировки.

Блокировка информационной базы может устанавливаться самой конфигурацией на время создания архивной копии. Если процесс ее создания не был завершен нормально, SQL-база может остаться в состоянии блокировки. В этом случае необходим доступ к консоли (более правильно – оснастке) «Администрирование серверов 1С:Предприятия».

Где ее искать?

Оснастка «Администрирование серверов 1С:Предприятия» часто установлена на том же сервере, где развернут SQL server, а также где развернут сам «Сервер 1С» (или «Сервер приложений 1С»). Хотя это и не обязательно: SQL может быть установлен на одном компьютере, «Сервер приложений 1С» – на другом, а оснастку можно развернуть и на своей рабочей станции. С большой вероятностью успеха можно достигнуть, сделав следующее:

  • Подключитесь по RDP к серверу, который указан в строке Srvr=… используя свой доменный логин и пароль. При невозможности подключения попросите системного администратора добавить вас в группу пользователей удаленного рабочего стола. (В случае отказа в таких правах – разверните и настройте на рабочей станции оснастку «Администрирование серверов предприятия 1С»);

  • На сервере найдите оснастку «Администрирование серверов 1С:Предприятия»;
  • Запустите оснастку, разверните дерево до узла с вашей информационной базой;

  • В свойствах информационной базы снимите чекбокс «Блокировка начала сеансов включена» или исправьте время начала и конца блокировки или посмотрите «код разрешения» для входа в ИБ (он же «код для разблокировки» в диалоге установки блокировки).

Что делать, если все пользователи информационной базы SQL вышли, а запустить Конфигуратор по-прежнему нельзя, т.к. имеются активные пользователи?

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


Это далеко не все вопросы, связанные с темой блокировки информационной базы.

Если у вас остались вопросы:

  • Можно ли работать по московскому времени, если вы арендуете сервер в Европе и не хотите зависеть от его часового пояса?
  • Как найти Сервер приложений 1С, если неизвестно, где он установлен?
  • Как развернуть оснастку «Администрирование серверов 1С:Предприятия» и как ее настроить?
  • Если в одной локальной сети несколько серверов приложений, как быть?
  • Как быть в случае кластерной системы? и т.д.

Наши сертифицированные консультанты по технологическим вопросам 1С с удовольствием на них ответят.

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

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

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

  • В автоматическом режиме все просто:
    • При любом чтении ставится S -блокировка .
    • А при любой записи ставится X -блокировка – причем, блокировки есть только на сервере СУБД , 1С никаких блокировок не ставит.
  • Гораздо больше интересен управляемый режим . Его главная особенность в том, что в 8.2 и в 8.3 блокировки работают по-разному .
    • Например, в 8.2 у вас любое чтение будет ставить S -блокировку . Причем, чтение – это не просто Запрос.Выполнить(), но и Ссылка.Реквизит, Ссылка.ПолучитьОбъект() и т.д.
    • А в 8.3 без режима совместимости уже блокировок на чтение не будет . Таким образом, 8.3 безусловно выигрывает в плане параллельности работы.
    • Ну а дальше начинается самое интересное – например, для конструкции НаборЗаписей.Прочитать() в управляемом режиме 8.2 у вас будет S-блокировка на сервере СУБД (это естественно). Но кроме этого также будет разделяемая блокировка на сервере 1С , причем это проявляется и в 8.2, и в 8.3 . И главная проблема в том, что эта разделяемая блокировка у вас будет длиться до конца транзакции – пока транзакция не закончится, данные будут блокированы.
      Поэтому рекомендация номер один – если набор записей вам нужен только для чтения, лучше использовать запрос, а не объектную модель. Тогда вы ничего блокировать не будете, а если и будете, то ненадолго.
    • Естественно, при любом изменении данных (запись, проведение, удаление) будет ставиться исключительная блокировка на сервере 1С и эксклюзивная на сервере СУБД .

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

Длительность блокировок в управляемом режиме

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

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

Что касается конструкции Запрос.Выполнить(), то если это 8.2, блокировка будет сниматься сразу после выполнения запроса, а если это 8.3 (либо в вашей СУБД MS SQL включен режим Read Committed Snapshot Isolation), тогда блокировки вообще не будет. Поэтому если у вас 8.2 или 8.3 в режиме совместимости с 8.2 , я вам всячески рекомендую включить режим Read Committed Snapshot Isolation – у вас в любом случае повысится параллельность работы.

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

Наиболее частые причины блокировок

Запрос со сканом

Чаще всего ожидание на блокировке возникает в случае неоптимального запроса . Например, у вас есть пользователь Иванов, который в процессе проведения документа заблокировал несколько позиций номенклатуры – только то, что ему было нужно. И есть пользователь Петров, который выполнил в транзакции запрос со сканированием (Запрос.Выполнить()). И если при чтении этот запрос нарвется на номенклатуру, которая была заблокирована Ивановым, то в случае использования вами версии 8.2 (либо 8.3 в режиме совместимости с 8.2), он остановится и будет ждать по умолчанию 20 секунд. При этом пользователь Петров встанет в ожидание, что, ему, конечно, не понравится. Как решить эту ситуацию? Казалось бы, ответ очевиден – можно взять и переписать запрос так, чтобы он не читал лишних строк , тогда все будет замечательно.

А если этот запрос платформенный? Или этот запрос используется в типовой конфигурации, которую вы по очевидным причинам изменять не можете – что тогда делать? Какие есть варианты?

Выключить режим совместимости? Правильнее сказать – перекреститься, создать копию, недельку потестировать и потом выключить, потому что если вы сразу выключите, у вас могут случиться «веселые выходные», а может быть не только выходные.

Еще один вариант – это включить режим версионирования для MS SQL Server . Сразу оговорюсь, что описанная ситуация возможна только в СУБД-блокировочнике, потому что если у вас СУБД-версионник, там этой ситуации быть не может. А если вы включаете Read Committed Snapshot Isolation, тогда у вас MS SQL начинает работать почти как версионник. И ваш запрос не будет блокировать строки .

В 1С нет «волшебной таблетки», но включение режима Read Committed Snapshot Isolation – ближайший аналог этой «волшебной таблетки» . Вы минимальными действиями сразу резко сможете снизить количество ожиданий в вашей базе. Для этого вам всего лишь нужно выполнить несколько строк приведенным на скриншоте скриптом в MS SQL сервере , и вы сразу получите очень хорошее повышение параллельности работы. Конечно, это имеет смысл только для управляемого режима блокировок в конфигурации 1С. Для автоматического режима включать на сервере СУБД режим RCSI смысла нет.

Отсутствие режима разделения регистров

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

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

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

Перемещение границы последовательности при проведении

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

Что тут можно сделать? Вы ставите свойство последовательности «Не перемещать автоматически» и делаете регламентное задание, которое в вечернее время у вас эту последовательность будет двигать . Вот такое простое решение – просто разбить по времени эти операции, тогда никаких ожиданий в течение дня уже не будет.

Длительные транзакции

Старайтесь делать максимально короткие транзакции:

  • Выносите всякие проверки и расчеты за пределы транзакции – любую запись, любое наложение блокировок надо делать в самом конце.
  • Ни в коем случае никаких диалоговых окон в транзакции делать не нужно, особенно, если используется толстый клиент. Мы сталкивались с такими случаями, что у бухгалтера при проведении документа выскакивало диалоговое окно с кнопками «Да» и «Нет». И пока она решит, что нажать, пока с кем-нибудь посоветуется, пока кому-то позвонит – у нее это окно будет висеть, и все это время транзакция будет активна, и, соответственно блокировка тоже будет активна – ее время будет очень долгим. Так делать не нужно.
  • Как можно еще ускорить время транзакции? Можно ускорить код , который там выполняется. Ускорить запросы , если вы это умеете делать. Это сразу даст резкий прирост производительности.
  • Еще один вариант – это ускорить запись в регистры . Как? Можно программным путем, а можно аппаратным. Например, если вы купили нормальные SSD-диски, то скорость записи у вас естественно вырастет – даже запросы станут выполняться быстрее. И, соответственно, время транзакции также уменьшится. Это не значит, что одним апгрейдом дисков можно решить проблему блокировок, но хотя бы можно сгладить этот эффект – он будет уже не так заметен.

Эскалация в многопоточном режиме

Я очень надеюсь, что многие из вас используют многопоточность для повышения производительности всяких загрузок, выгрузок, перепроведения документов, при свертке больших объемов данных. Это действительно мощная возможность, которая позволяет получить ускорение в несколько раз. Однажды мне необходимо было свернуть регистр, содержащий более 100 миллионов строк, причем, неактуальные остатки нужно было куда-то выгрузить, оставив в базе только некоторый актуальный промежуток времени. Я подумал и решил реализовать для этого случая многопоточную обработку. В результате у меня получилось, что эти потоки стали блокировать друг друга, хотя их данные вообще никак не пересекались (в каждом потоке были разные регистраторы) – тем не менее, возникало ожидание на блокировке.

Выяснилось, что в одном из потоков был большой, тяжелый документ, который приводил к эскалации. Эскалация – это когда блокировка накладывается не на какую-то строку в таблице, а сразу на всю таблицу . И в моем случае в одном из потоков как раз и происходила блокировка вообще всей таблицы.

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

Когда обычно в 1С возникает эскалация? Чаще всего это какая-то тяжелая операция – закрытие месяца, расчет себестоимости и пр. – когда у вас в одной гигантской транзакции начинает проводиться много документов, блокируется вся таблица и в это время никто работать не может – параллельность падает. Такие операции необходимо учитывать отдельно и проводить их в нерабочее время , потому что в параллельном режиме вы их обработать не сможете.

Ошибка платформы – блокировка при использовании разделителя области данных

В платформе есть несколько ошибок, которые приводят к излишним ожиданиям на блокировке. Например, есть ошибка, которая меня очень удивила. Ситуация следующая – мы собрали данные об ожиданиях и увидели, что строка Запрос.Выполнить() накладывает управляемую исключительную блокировку, чего в принципе быть не может и не должно. Когда мы это увидели, мы подумали, что инструмент «сбоит». Еще раз загрузили данные. Все перепроверили. Действительно, накладывает. Оказалось, что такая ошибка появилась в платформе 8.3.6. При чтении – неважно, Запрос.Выполнить() или Константа.Прочитать() – вообще при любом чтении – платформа накладывала управляемую исключительную (Х) блокировку на поле, которое является разделителем данных и параллельность сразу падала. Причем, блокировка была именно исключительной.

Вот такая платформенная ошибка.

К счастью для нас клиент, у которого эта проблема проявилась, вообще не использовал этот разделитель данных, поэтому мы просто у реквизита сняли признак того, что он является разделителем. И все, ошибка исчезла. Но исправлена она или нет, я до сих пор не знаю. Могу точно сказать, что в 1С про эту ошибку знают, но когда они ее исправят, мне, к сожалению, не известно. Поэтому будьте готовы, что у вас такое тоже может быть.

Ошибка платформы – скан индекса регистра расчета

Также мы часто сталкиваемся с ошибками платформы по работе с регистром расчета. С точки зрения производительности у него вообще проблем очень много, потому что регистр расчета – это единственный объект в 1С, который не имеет кластерного индекса . Поэтому, когда вы записываете в регистр расчета несколько сотен строк (если строк мало, то эта ошибка не воспроизводится), или чистите там движения (записываете туда пустой набор движений) – будет производиться скан индекса таблицы регистра расчета . А поскольку это запрос платформенный, вы его поправить никак не сможете, и, так как это – удаление (накладывается X блокировка), то включение режима Read Committed Snapshot тоже никак не меняет ситуацию.

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

Еще одна проблема регистра расчета проявляется при чтении и заключается в том, что платформенный запрос, который читает данные из регистра расчета, тоже сканирует индекс. Но здесь уже помогает именно включение либо Read Committed Snapshot, либо, если у вас 8.3, вы можете убрать режим совместимости с 8.2, тогда этой проблемы у вас уже не будет.

Ошибка платформы – невозможность параллельной записи в периодический независимый регистр сведений

Очень старая ошибка, про которую в 1С тоже прекрасно знают, но, тем не менее, она до сих пор не исправлена – это невозможность параллельной записи в периодический независимый регистр сведений . Казалось бы, если у вас периоды разные (измерения совпадают, но периоды разные), вы могли бы записывать туда данные параллельно. Но этого не происходит, хотя должно бы быть. Потому что на сервере 1С накладывается излишняя блокировка по дате . На проектах эта ситуация встречается не часто – регистр сведений очень редко становится «узким местом» для блокировок. Обычно проблемы возникают из-за регистра накопления, либо из-за регистра бухгалтерии. Но, тем не менее, если вы с этим столкнетесь, можете попробовать сделать период измерением . Да, конечно, в этом случае никаких виртуальных таблиц (срез первых, срез последних) этот регистр сведений формировать уже не будет, но зато вы сможете спокойно писать в него параллельно, а запрос для получения среза первых/последних можно и самим формировать.

  • Во-первых, переходите на управляемый режим блокировок . Я думаю, это довольно очевидно, потому что если у вас используется автоматический режим, вы можете даже не удивляться вопросам «Почему у нас параллельность работы маленькая, почему много блокировок?» Сначала перейдите на управляемый режим, и, если после этого у вас проблемы останутся, тогда уже можно будет дальше разбираться.
  • Когда перевели конфигурацию в управляемый режим блокировок, обязательно должен быть включен режим СУБД Read Committed Snapshot Isolation . Это прямо Must Have –сразу будет резкий прирост по параллельности работы.
  • Используйте разделитель итогов для регистров . Там, где нет контроля остатков, обязательно нужно включить, чтобы не было ожиданий.
  • И НаборЗаписей.Прочитать() – старайтесь вообще для чтения не использовать , потому что при этом будет наложена управляемая блокировка, которая будет «висеть» до конца транзакции. Зачем вам это нужно? Читайте данные запросом, и блокировок тогда вообще не будет, если у вас 8.3 без режима совместимости или включен режим Read Committed Snapshot.
  • По поводу границы последовательности – тоже постарайтесь принять по умолчанию, что границу двигать только регламентным заданием в нерабочее время . При проведении не двигать.
  • Большие транзакции делить на несколько . Чем проводить миллион документов в одной транзакции, лучше сделать мелкие транзакции по 100 документов, по 1000 документов – еще лучше, если в многопоточном режиме. Это будет более стабильно.
  • Всякие расчеты, проверки и пр. делайте за пределами транзакции . Время транзакции должно быть минимальным, как можно меньше.

Пример решения проблемы блокировок

Как еще можно избавиться от излишних ожиданий?

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

Как этого можно избежать? Можно при загрузке документы создавать, но не проводить , а потом написать механизм, который , например, реализует это дальнейшее проведение в многопоточном режиме , где каждый поток будет проводить документы по своему складу. Разнести, таким образом, эти процессы во времени: первый поток проводит документы по одному складу, второй поток – по второму складу и т.д. Тогда проблема будет решена.

Блокировки и оборудование

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

Как влияет на оборудование оптимизация блокировок? Например, вы с автоматического режима перешли на управляемый, или взяли и включили Read Committed Snapshot. Пока система ждет , она оборудование не использует и оно у вас в этом случае простаивает . А как только у вас система заработала на полную мощность, ожиданий нет , у вас сразу идет резкий прирост, . И, в зависимости от того, в каком состоянии оно у вас на данный момент находится, это может быть критично. Например, если сервер у вас был загружен на 80%, а вы еще и блокировки свои устранили, он вообще может «лечь». Это обязательно нужно учитывать.

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

Инструмент для анализа блокировок

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

О пользе перехода на управляемые блокировки в 1С 8.3 было сказано не раз — это сильно повышает эффективность и производительность работы оборудования.

Если Вам необходим партнер для перевода конфигурации в управляемый режим блокировок, просто обратитесь к нам! Подробности — .

Сам по себе процесс не такой уж и трудный. Однако процесс достаточно тонкий. Переход на управляемый режим неквалифицированным специалистом может сделать еще хуже.

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

Вся методика умещается в 7 коротких пунктах:

Переключите в палитре свойств конфигурации режим блокировок — «Управляемый и автоматический»:

Получите 267 видеоуроков по 1С бесплатно:

Переключение объекта в управляемый режим

Необходимо начинать с самых «загруженных» документов. Переключите документ в режим блокировок «Управляемый»:

Перевод регистров в управляемый режим

Необходимо перевести ВСЕ регистры 1С (накопления, бухгалтерии, сведений, расчета), которые производят движения данным документом, в режим управляемых блокировок:

Найти все транзакции с этими объектами

Необходимо найти все транзакции с этими объектами метаданных. Как явные, так и не явные.

Явные — те, которые вызываются в коде с помощью метода «НачатьТранзакцию()».

НЕ явные — те, которые вызываются в обработчиках объектов — «ПриЗаписи», «ОбработкаПроведения» и т.д.

Корректировка программного кода в транзакция

Для явных транзакций необходимо передать в параметр метода «НачатьТранзакцию()» параметр «РежимУправленияБлокировкойДанных.Управляемый».

Для НЕ явных транзакций установить блокировки с помощью объекта системы «БлокировкаДанных».

Пример использования блокировки:

Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить(«РегистрНакопления.ТоварыНаСкладах»);
ЭлементБлокировки.УстановитьЗначение(«Качество», Справочники.Качество.НайтиПоКоду(«1»));
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.ИсточникДанных = ДокументОбъект.ВозвратнаяТара;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(«Номенклатура», «Номенклатура»);
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(«Склад», «Склад»);
Блокировка.Заблокировать();

Заменить конструкцию ДЛЯ ИЗМЕНЕНИЯ

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

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

И так, поехали…

Сперва напишу про уровни изоляции транзакций, кратко рассмотрю только те уровни, которые имеют отношение к данной статье.

Уровни изоляции транзакций

Read committed (чтение завершенных) - разрешено чтение данных в транзакции, изменения по которым были завершены всеми остальными транзакциями. По умолчанию используется для большинства баз данных.

Read committed Snapshot (версионирование данных) - разрешено чтение старой версии данных, изменения по которым не завершены другими транзакциями. Штатно поддерживается базами данных: Postgre SQL и Oracle . Начиная с версии платформы 1С 8.3 реализован для работы с базами данных: MSSQL .

Repeatable read (повторяемое чтение) - запрет на изменение записей в транзакции, которые уже были считаны ранее в рамках остальных транзакций.

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

Разделение итогов регистров накопления

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

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

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

Механизмы контроля остатков в типовых конфигурациях 1С

Старая схема, далее OLD - формируется запрос к базе данных для выполнения контроля свободных остатков, в случае положительного решения, формируется движение по регистру. На данный момент применяется в Бухгалтерии 3.0 и в некоторых алгоритмах УТ 11, КА 2, ЕРП 2.

Недостатки :

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

Новая схема, далее NEW - выполняется движение по регистру, затем проверяется наличие отрицательных остатков, в случае их наличия, операция откатывается. На данный момент применяется в УТ 11, КА 2, ЕРП 2.

Преимущества:

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

Недостатки :

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

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

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

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

Режим автоматических блокировок

В данном случае используется описанный выше режим изоляции транзакций: Repeatable read .

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

Для исключения взаимоблокировок при проведении документов с контролем остатков - OLD применяется конструкция языка запросов «ДЛЯ ИЗМЕНЕНИЯ », позволяющая при первом чтении данных в транзакции наложить на эти данные не разделяемую блокировку на чтение, а блокировку обновления. Соответственно, в другой транзакции уже будет невозможно выполнить подобную процедуру, так как наложить на одни и те же данные две блокировки обновления из разных транзакций нельзя .

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

Примечание: В случае работы с файловой базой и с P postgre SQL , блокировка накладывается целиком на всю таблицу.

Пример:

ВЫБРАТЬ ОстаткиТоваров.Номенклатура, ОстаткиТоваров.КоличествоОстаток КАК Количество ИЗ РегистрНакопления.ОстаткиТоваров.Остатки КАК ОстаткиТоваров ДЛЯ ИЗМЕНЕНИЯ

Использовать режим контроля остатков - NEW совместно с автоматическим режимом блокировок имеет смысл только для регистров без разделения итогов, в этом случае, никаких дополнительных действий делать не нужно. При использовании регистров с разделением итогов может возникнуть d ea dlock на чтении данных, если запись в регистр производилась одновременно, и каким-то образом решить данную проблему не получится.

Режим управляемых блокировок

В данном случае, применяется режимы изоляции транзакций: Read committed и Read committed Snapshot .

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

Пример:

БлокировкаДанных = Новый БлокировкаДанных; ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрНакопления.ТоварыНаСкладах.НаборЗаписей"); ЭлементБлокировки.УстановитьЗначение("Склад", Склад); ЭлементБлокировки.УстановитьЗначение("Номенклатура", Номенклатура); ЭлементБлокировкиДанных.Режим = РежимБлокировкиДанных.Исключительный; БлокировкаДанных.Заблокировать();

Использование режима контроля остатков NEW :

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

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

  • Без режима версионирования (MS SQL и 1С 8.2) - получим взаимоблокировку при попытке чтения данных, если запись в двух транзакциях была выполнена одновременно. При записи данных блокировка не будет возникать, так как используются разные строки СУБД (разделение итогов)
  • С режимом версионирования Snapshot (postgresql, oracle или 1С 8.3) - блокировка возникать не будет, но будут появляться отрицательные остатки, так как контроль будет выполнен без учета всех не завершенных транзакций.

Для исключения подобной ситуации необходимо перед записью в регистр установить флаг набора записей: БЛОКИРОВАТЬ ДЛЯ ИЗМЕНЕНИЯ . Данная конструкция дает команду при записи накладывать исключительную блокировку на записи таблицы остатков регистра без учета разделителя итогов, по своей сути, она просто напросто временно отключает разделение итогов для регистра накопления.

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

Пример:

НаборЗаписей. БлокироватьДляИзменения = Истина;

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

Если что-то упустил и в чем-то был не точен, буду руд увидеть это в комментариях к статье.

Отдельное огромное спасибо, если отметите статью звездочкой, так как не что так не мотивирует на написание новых статей, как Ваше одобрение J