Блокировка данных, которые читаются и изменяются при проведении
страницаБлокировка данных, которые читаются и изменяются при проведении
Казалось бы, это все? Но нет, есть очень важный момент, о котором также нужно позаботиться.
Сейчас схема вашей процедуры такова:
- Вы выполняете первый запрос с именем
Запрос. В результате вы формируете временную таблицу из перечня номенклатуры документа. - Вы выполняете второй запрос с именем
Запрос2. В результате вы читаете стоимость и остатки для номенклатуры, содержащейся в табличной части документа. - Вы записываете движения регистров (Движения.Записать()).
- Вы выполняете третий запрос с именем
Запрос3. Тем самым вы проверяете наличие отрицательных остатков.
Обратите внимание, что начиная с выполнения второго запроса и до конца процедуры вам необходимо обеспечить неизменность стоимости и остатков номенклатуры, с которой вы работаете, и запретить другим транзакциям даже читать эти данные. Сама система, естественно, заблокирует изменение этих данных, но лишь начиная с того момента, когда вы запишете движения.
Однако может возникнуть следующая ситуация. Выполняя второй запрос, вы прочитали, что есть 2 шт. некоторого материала. И другая транзакция (другой пользователь), которая собирается списывать материалы, тоже прочитала, что есть 2 шт. этого материала. После этого вы записали движения, и система заблокировала эти данные. Другая транзакция ждет, когда вы освободите данные. Вы провели документ, списали 2 шт. материала и освободили данные. Другая транзакция пытается тоже списать 2 шт. материала, но его уже нет!
Аналогичная ситуация может возникнуть и между п. 3 и п. 4, в результате чего контроль остатков будет работать неверно.
Поэтому, чтобы не происходило таких коллизий, вам необходимо заблокировать остатки от чтения другими транзакциями еще до выполнения второго запроса. То есть, прежде чем читать что-то, что вы собираетесь изменять, нужно запретить чтение этих данных другими транзакциями до тех пор, пока вы не закончите свои изменения (или пока не откажетесь от проведения документа).
Как это сделать? Хороший вопрос. Посмотрите на свойство Режим управления блокировкой данных вашей конфигурации. Оно установлено в значение Управляемый (рис. 15.21).

Рис. 15.21. Режим управления блокировкой данных в свойствах конфигурации
Это значит, что вам нужно использовать управляемые блокировки, которые устанавливаются средствами встроенного языка.
Необходимо заблокировать те данные, которые вы собираетесь читать и впоследствии изменять. Для этого у наборов записей регистров есть свойство БлокироватьДляИзменения, которым вам и нужно воспользоваться.
Вставьте этот код перед выполнением второго запроса (листинг 15.25).
**Листинг 15.**25. Фрагмент процедуры «ОбработкаПроведения()»
…
| ПО НоменклатураДокумента.Номенклатура = СтоимостьМатериаловОстатки.Материал";
Запрос2.УстановитьПараметр("Период", МоментВремени());
// Установить необходимость блокировки данных в регистрах СтоимостьМатериалов и ОстаткиМатериалов.
Движения.СтоимостьМатериалов.БлокироватьДляИзменения = Истина;
Движения.ОстаткиМатериалов.БлокироватьДляИзменения = Истина;
РезультатЗапроса = Запрос2.Выполнить();
Управляемая блокировка будет установлена в момент записи этих наборов записей, то есть как раз перед выполнением второго запроса. Что вам и требовалось.