Запись движений при проведении появилась в релизе. V8: Добавление и правка движений в конце проведения документов

Для определения возможности оптимизации блокировок в1С:Підприємство необходимо .

Так, используемый по умолчанию уровень изоляции Read Committed использует следующие блокировки:

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

Что бы уменьшить время и количество «S» блокировок при чтении данных , необходимо оптимизировать запросы так, что бы они выполнялись быстро и без лишних блокировок (этот вопрос будет обсуждаться в отдельном разделе «Оптимизация запросов»). При записи - изменять данные как можно ближе к концу транзакции. Для этого в платформе предусмотрены следующие настройки:
Режим удаления движений документа (вкладка «Движения»):
удалять автоматически при отмене проведения – по умолчанию;
удалять автоматически – движения удалятся (запишутся пустые наборы непосредственно перед обработкой проведения и установится X блокировка до конца транзакции);
не удалять автоматически.

Если движения автоматически не удаляются, то это может повлиять на алгоритм проведения (например на контроль остатков). Тогда необходимо записать пустой набор непосредственно перед запросом остатков:
// Запишем пустые наборы записей, чтобы читать резервы без учета данных в документе.
Движения.РезервыНоменклатуры.Записать();
Результат = Запрос2.Выполнить();

Также надо учитывать существующие записи при использовании записи с добавлением записей из набора «Записать(Ложь) »

Варианты записи движений:
1. Запись вручную каждого набора используя «Движения.ИмяНабора.Записать() »;
2. Запись определенного списка наборов в соответствии со свойством документа «Запись движений при проведении»:
Свойство документа «Запись движений при проведении» определяет список наборов для записи:
«Записывать выбранные» - устанавливается по умолчанию. При этом список наборов для записи определяется свойством «Записывать» каждого набора (Движения.ИмяНабора.Записывать = Истина )
«Записывать модифицированные» — при этом список наборов для записи будет состоять из наборов с установленным свойством «Модифицированность».

В соответствии со свойством «Запись движения при проведении» все «Выбранные» или «Модифицированные» наборы записей записываются автоматически непосредственно после обработки проведения:
КонецПроцедуры //Обработка проведения
Наборы записываются последовательно в соответствии с их порядком в дереве конфигурации:

  • Регистры сведений;
  • Регистры накопления;
  • Регистры бухгалтерии;
  • Регистры расчета .

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

Не путать метод «Записать()» коллекции движений «Движения» с методом «Записать()» набора записей (элемента коллекции движений).
После записи набора, независимо каким способом он записан, его свойства «Записывать» и «Модифицированность» сбрасываются в «Ложь».

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

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

Использование обработчиков событий в транзакции

Запись документа (объекта) происходит между обработчиками «ПередЗаписью()» и «ПриЗаписи()». В обработчике «ПриЗаписи()» уже можно использовать ссылку на объект.

Так же между обработчиками «ПередЗаписью()» и «ПриЗаписи()» происходит заполнение регистрации в последовательности, если для документа установлено автоматическое заполнение последовательности. В обработчике «ПриЗаписи()» можно изменить или очистить набор регистрации в последовательности.

Если для документа установлен параметр «Автоматическое удаление движений при проведении», то движения документа удаляются непосредственно перед обработчиком «ОбработкаПроведения()». Автоматическая запись движений документа (наборов с установленным признаком модифицированности или «Записывать») производится непосредственно после обработчика «ОбработкаПроведения()». Процедура «ОбработкаПроведения()» и связанные с нею операции автоматического удаления/записи движений выполняются только если документ записывается в режиме записи «Проведение».

Все обработчики, которые выполняются в транзакции имеют параметр «Отказ». Но не наоборот! Есть обработчики, которые имеют параметр «Отказ», но выполняются вне транзакции. Это обработчики, которые выполняются до транзакции, например обработчик формы «ПередЗаписью()».

В случае управляемого интерфейса имеются ввиду именно серверные процедуры «ПередЗаписьНаСервере()», «ПриЗаписиНаСервере()» и «ПослеЗаписиНаСервере()».

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

В таблицы итогов регистров хранятся итоговые данные (Начальные остаток, Приход, Расход, Конечный остаток) в разрезе всех измерений с периодичностью «Месяц». Также в таблицах итогов регистров накопления остатков и бухгалтерии хранятся текущие итоги, с периодом 3999 год (если используется смещение дат, то 5999).
При параллельной записи в таблицы итогов (из разных сеансов, разными регистраторами) по одинаковым наборам измерений и периода (полей) возникает ожидание блокировки:

Для исключения таких блокировок применяется разделитель итогов - в таблицы итогов добавляется служебное поле «Splitter». Каждому одновременно работающему сеансу назначается свое значение разделителя. Каждый сеанс записывает данные в таблицы итогов со своим значением разделителя. В таблице итогов будет столько разных значений разделителя сколько одновременных сеансов будут вести запись в регистр. Также поле «Splitter» включается в кластерный индекс таблицы итогов. Так как при использовании разделителя одновременные сеансы записывают данные в таблицы итогов по разному составу полей (из-за значения разделителя), блокировки при записи исключаются:

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


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

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

Уровень изоляции READ_COMMITTED_ SNAPSHOT в версии 8.3

Платформа версии 8.3 применяется модифицированный уровень изоляции READ_COMMITTED_SNAPSHOT , появившийся в В MS SQL Server 2005 и реализующий режим версионирования , не использовавшийся в СУБД MS SQL ранее. Поведение на уровне READ COMMITTED зависит от настройки аргумента базы данных READ_COMMITTED_SNAPSHOT .
Если параметр READ_COMMITTED_SNAPSHOT находится в состоянии OFF, компонент Database Engine при выполнении операций считывания текущей транзакцией для предотвращения изменения строк другими транзакциями использует разделяемые блокировки. Разделяемые блокировки также блокируют инструкции от считывания строк, измененных другими транзакциями, пока не завершится другая транзакция. По завершении инструкции разделяемые блокировки снимаются.
Если параметр READ_COMMITTED_SNAPSHOT находится в состоянии ON, компонент Database Engine использует управление версиями строк для представления каждой инструкции согласованного на уровне транзакций моментального снимка данных в том виде, который они имели на момент начала выполнения инструкции. Для защиты данных от обновления другими транзакциями блокировки не используются.

Как работает версионирование

Например есть несколько, параллельно выполняющихся, транзакций, читающие одни и те же данные. В обычном режиме READ_COMMITTED, MS SQL Server перед чтением делает попытку наложить разделяемую блокировку на нужный ресурс (S блокировка при чтении). При включенном версионировании вместо попытки установки разделяемой блокировки, транзакция прочитает нужные данные из базы tempdb, куда транзакция, которая успела изменить данный, скопировала версию данных до изменения. При изменении данных в транзакции с уровнем изоляции READ_COMMITTED_SNAPSHOT версия данных до изменения предварительно помещается из основной базы в tempdb. После выполнения транзакции, помещенная ею в tempdb версия данных будет удалена.

SQL команды установки параметров уровня изоляции после реструктуризации:

Запуск 1С:Підприємство при установке совместимости 8.2:

ALTER DATABASE test83 SET READ_COMMITTED_SNAPSHOT OFF WITH ROLLBACK IMMEDIATE
SET LOCK_TIMEOUT 20000

Запуск 1С:Підприємство при установке совместимости 8.3:
ALTER DATABASE test83 SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE
SET LOCK_TIMEOUT 20000
SET TRANSACTION ISOLATION LEVEL READ COMMITTED

Определить состояние базы можно запросом:
select name,snapshot_isolation_state_desc,is_read_committed_snapshot_on from sys.databases

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

Настройки документа :

Если посмотреть свойства документа через палитру свойств, то можно увидеть два важных свойства: "Удаление движений" и "Запись движений при проведении", причем второе НЕ вынесено на закладку "Движения" окна редактирования документа.

1. Удаление движений.

Если свойство "Удаление движений" уставновлено в "Удалять автоматически", то ПЕРЕД началом проведения программа очищает все движения по регистрам. Фактически это означает запись пустого набора записей регистра с видом записи - замещение. А значит, программа выполняет код из процедур "ПередЗаписью" и "ПриЗаписи" модуля набора записей регистров.

Если для какого-либо регистра определена подписка на событие "При записи", то выполняется код из связанной процедуры.

2. Процедура "ОбработкаПроведения" модуля документа.

Обратим внимание: в начале обработки проведения у всех движений флаг модифицированности Ложь (значение возвращает метод Движения.Регистр.Модифицированность() ).

При работе с набором записей регистра (например, Движения.Регистр.Очистить() , Движения.Регистр.Добавить() и т.д.) флаг модифицированности становится Истина.

После записи движения в базу Движения.Регистр.Записать() модифицированность снова ложь.

Если в модуле процедуры подписки происходит запись набора регистра в явном виде (.Записать() ), то программа выполняет код из процедур "ПередЗаписью" и "ПриЗаписи" модуля набора записей регистров и процедуры из подписки на событие "При записи" регистра.

3. Подписки на событие "При проведении" документа

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

Процедура ПриПроведенииДокумента(Источник, Отказ, РежимПроведения) Экспорт Регистр = Источник.Движения.Бухучет; ..... КонецПроцедуры

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

Если регистры записываются с помощь метода Записать() , то выполняются все связанные процедуры.

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

Вспомним про свойство "Запись движений при проведении" из настроек документа.

Если оно равно "Записывать модифицированные", то в базу будут записаны все движения документа, у которых флаг "Модифицированность" Истина.

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

Движения.Регистр.Записывать = Истина;

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

И в конце рассмотрим несколько примеров:

Пусть свойство документа "Запись движений при проведении" равно "Записывать модифицированные", а "Удаление движений" - "Не удалять автоматически".

Пример 1.

Процедура ОбработкаПроведения(Отказ, РежимПроведения) НовЗапись = Движения.Регистр.Добавить(); .... Движения.Регистр.Записать(Ложь); //*** КонецПроцедуры

При такой процедуре проведения документ при каждом перепроведении будет добавлять запись в регистр, записи будут множиться. Т.к. строка //*** добавляет записи в регистр, признак Модифицированности снимается.

Правильнее будет написать строку //*** как

Движения.Регистр.Записать()

или вообще ее опустить, и тогда программа сама запишет модифицированные движения.

Пример 2.

В 1С 8 движения документа могут формироваться не только в обработке проведения, но и извне, например, из некоторой служебной обработки (так реализовано допроведение документов, восстановление авансов и т.д.).

Приход = Документы.ПриходнаяНакладная.Выбрать(); Проводки = РегистрыБухгалтерии.Регистр.СоздатьНаборЗаписей(); Пока Приход.Следующий() Цикл ДокСсылка = Приход.Ссылка; Проводки.Отбор.Регистратор.Установить(ДокСсылка); НоваяПроводка = Проводки.Добавить(); НоваяПроводка.Период = ДокСсылка.Дата; НоваяПроводка.Организация = ДокСсылка.Организация; НоваяПроводка.СчетДт = ПланыСчетов.ПланСчетов.Товары; НоваяПроводка.СчетКт = ПланыСчетов.ПланСчетов.Поставщики; НоваяПроводка.Сумма = ДокСсылка.Всего; Проводки.Записать(Ложь); КонецЦикла;

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

Пример 3.

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

Если в процессе проведения документа движения по регистрам формируются не с помощью коллекции Движения, принадлежащей внутреннему объекту , а другими способами (вручную в форме набора записей или как в примере 2 и т.д.), то на этапе 4 эти записи будут замещены!!! Чтобы избежать замещения в типовых базах, для документа "ОперацияБух" свойство документа "Проведение" устанавливается в "Запретить".

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

Выбрать вариант записи движений "Записывать выбранные" и убедиться, что Движения.Регистр.Записывать = Ложь

Выбрать вариант записи движений "Записывать модифицированные" и контролировать признак Модифицированности для набора записей этого регистра.

Пример 4 .

Нужно понимать, что объект, полученный по ссылке (назовем его "ОбъектДок"), и внутренний объект ("ЭтотОбъект"), созданный в памяти в момент проведения, это два разных экземляра объектов.

Соответственно и коллекции движений у них будут разные. У "ОбъектаДок" коллекция движений будет включать только записанный в базу набор записей регистра, а у "ЭтогоОбъекта" - как записанные, так и добавленные и незаписанные записи. По окончании проведения (этап 4) в базу будут записаны наборы записей "ЭтогоОбъекта", причем с признаком Замещать = Истина.

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

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

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


Рис. 5.12.

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

  • Проведение . Может принимать значения Разрешить и Запретить . Определяет возможность проведения документа .
  • Оперативное проведение . Так же принимает значения Разрешить и Запретить . Оперативное проведение - это проведение документа в режиме реального времени. При оперативном проведении документ получает оперативную отметку времени, которая либо соответствует текущему системному времени, либо превышает его - в том случае, если другой документ получил оперативную отметку времени, равную текущему системному времени. В итоге, документы , проведенные в оперативном режиме, выстраиваются в логически верную последовательность, соответствующую последовательности их ввода. При оперативном проведении документов производится контроль различных параметров реального времени. Например, если документ , проводимый оперативно, должен списывать какие-либо материалы, можно осуществить контроль фактического наличия материалов. Если дата документа отличается от текущей, документ может быть проведен в неоперативном режиме.
  • Удаление движений . По умолчанию этот параметр установлен в значение Удалять движения автоматически . Такая установка позволяет автоматически удалять движения, сформированные документом ранее, при перепроведении документа или при отмене проведения. Если вы хотите управлять удалением движений самостоятельно (например, для того, чтобы ускорить работу системы при перепроведении больших документов ), это свойство можно установить в значение Не удалять движения автоматически , но тогда удалять ненужные движения придется, используя средства встроенного языка.

Сейчас мы готовы к тому, чтобы настроить процедуру проведения документа . Нажмем на кнопку Конструктор движений . Появится форма конструктора ( рис. 5.13).


Рис. 5.13.

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

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

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

Автоматическое заполнение производится, во-первых, с учетом типов, во-вторых, с учетом названий. На рис. 5.14 вы можете видеть окно конструктора движений после выбора в поле Табличная часть табличной части Материалы и нажатия на кнопку Заполнить выражения .


Рис. 5.14.

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

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


Рис. 5.15.

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

ТекСтрокаМатериалы.Номенклатура ТекСтрокаМатериалы.Количество ТекСтрокаМатериалы.Сумма

Сейчас работа с конструктором движений завершена, нажмем на кнопку ОК . Будет сформирована процедура, которая сработает при проведении документа , рис. 5.16 .

Ниже приведен текст процедуры:

Процедура ОбработкаПроведения(Отказ, Режим) //{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ // Данный фрагмент построен конструктором. // При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!! Для Каждого ТекСтрокаМатериалы Из Материалы Цикл // регистр ОстаткиМатериалов Приход Движение = Движения.ОстаткиМатериалов.Добавить(); Движение.ВидДвижения = ВидДвиженияНакопления.Приход; Движение.Период = Дата; Движение.Номенклатура = ТекСтрокаМатериалы.Номенклатура; Движение.ЦентрОтветственности = ОтветственныйСотрудник; Движение.Количество = ТекСтрокаМатериалы.Количество; Движение.Сумма = ТекСтрокаМатериалы.Сумма; КонецЦикла; //}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ КонецПроцедуры

Эта процедура расположена в модуле объекта - то есть - документа .

Основой процедуры является цикл:

Для Каждого ТекСтрокаМатериалы Из Материалы Цикл КонецЦикла;

Этот цикл выполняется для каждой строки (на нее ссылается переменная ТекСтрокаМатериалы ) табличной части Материалы . То есть, в цикле последовательно перебираются все строки табличной части

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

  • Записать
  • Провести
  • Провести и закрыть
  • Отмена проведения
Рассмотрим последовательность выполнения событий при каждом действии.

Действие Записать

Для непроведенного документа последовательность выполнения событий при записи документа из формы будет следующей:
  1. Модуль объекта - перед записью (начинается транзакция, документ еще не записан);
  2. Модуль формы (&НаСервере) - при записи на сервере (фиксация транзакции);
Заметим, что для расширения формы документа платформа 1С по-умолчанию устанавливает значение Истина для свойства ПриЗаписиПерепроводить , поэтому, при записи проведенного документа из формы платформа 1С выполнит автоматически его перепроведение. В этом случае для проведенного документа последовательность выполнения событий при записи из формы будет следующей:
  1. Модуль формы (&НаКлиенте) - перед записью;
  2. Модуль формы (&НаСервере) - обработка проверки заполнения на сервере;
  3. Модуль объекта - обработка проверки заполнения;
  4. Модуль формы (&НаСервере) - перед записью на сервере;
  5. Модуль объекта - перед записью (начало транзакции, документ еще не записан);
  6. Модуль объекта - при записи (документ записан);
  7. Модуль объекта - обработка проведения (формирование набора записей движений документа);
  8. Модуль формы (&НаСервере) - при записи на сервере (записан набор записей движений документа, фиксация транзакции);
  9. Модуль формы (&НаСервере) - после записи на сервере;
  10. Модуль формы (&НаКлиенте) - после записи.
Если для свойства ПриЗаписиПерепроводить установить значение Ложь , тогда последовательность выполнения событий при записи проведенного документа из формы будет такой же как и для непроведенного документа.

Последовательность выполнения событий при записи документа из формы, у которого запрещено проведение (свойство Проведение установлено в значение Запретить ) будет следующей:
В отличии от документа, у которого разрешено проведения, в этом случае отсутствует событие ОбработкаПроведения . Но, при записи проведенного документа с перепроведением и при записи документа, у которого запрещено проведение, кроме самой записи, в контексте формы и в контексте объекта вызывается также событие ОбработкаПроверкиЗаполнения . Это событие вызывается расширением формы для проверки заполнения реквизитов при записи или при проведении документа в форме.

Действие Провести

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

Действие Провести и закрыть

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

Действие Отмена проведения

Данное действие инициирует запись документ и запускает следующую последовательность событий:
  1. Модуль формы (&НаКлиенте) - перед записью;
  2. Модуль формы (&НаСервере) - перед записью на сервере;
  3. Модуль объекта - перед записью (начало транзакции);
  4. Модуль объекта - обработка удаления проведения (удаление движений);
  5. Модуль объекта - при записи (движения удалены, документ записан);
  6. Модуль формы (&НаСервере) - после записи на сервере (фиксация транзакции);
  7. Модуль формы (&НаКлиенте) - после записи.
Если действия выполняются не из формы (выполняются программно), отличия состоя в том, что не выполняются события формы!

Просмотров