Вопрос 1.1
Вопрос имеет несколько решений в зависимости от версии платформы 1С и режима управления блокировкой данных в конфигурации.
В версии платформы <8.2.14 константы хранятся в одной таблице _Consts в одной строке в разных колонках:
Начиная с 1С 8.2.14 для каждой константы определена отдельная таблица:
Рассмотрим, какие блокировки будут накладываться при чтении в транзакции и вне транзакции в СУБД MS SQL 2014 при автоматическом режиме управления блокировкой данных:
1С 8.2.13 | Чтение константы в транзакции методом Получить() в автоматическом режиме |
![]() |
|
Установлена разделяемая блокировка (S) на единственную запись в кластерном индексе _Consts_ByKey_B таблицы _Consts, а также блокировки намерения IS на страницу индекса _Consts_ByKey_B и на всю таблицу. |
1С 8.2.13 | Чтение константы в транзакции запросом в автоматическом режиме |
![]() |
|
Установлена разделяемая блокировка диапазона RangeS-S на единственную запись кластерного индекса _Consts_ByKey_B, блокировки намерения IS на страницу кластерного индекса _Consts_ByKey_B и на всю таблицу. |
Переведём конфигурацию в управляемый режим, включим в ТЖ отслеживание событий TLOCK и SDBL к исследуемой базе. Проведём аналогичный эксперимент по чтению в транзакции константы методом Получить() и запросом.
После выполнения запроса установленных управляемых блокировок 1С и блокировок СУБД не зафиксировано.
Во время работы метода Получить() и выполнения запроса на строки, выбираемые запросом, накладывалась S-блокировка. После чтения строк данная блокировка снималась.
Изменим версию совместимости на 8.2.16. Повторим эксперимент в автоматическом режиме:
1С 8.2.16 | Чтение константы в транзакции методом Получить() в автоматическом режиме |
![]() |
|
Установлена S-блокировка на запись кластерного индекса _Const1832_ByKey_B, блокировки намерения IS на страницу кластерного индекса и на всю таблицу. Видно, что для каждой константы используется своя таблица. |
1С 8.2.16 | Чтение константы в транзакции запросом в автоматическом режиме |
![]() |
|
Установлена разделяемая блокировка диапазона RangeS-S на единственную запись кластерного индекса _Const1832_ByKey_B, блокировки намерения IS на страницу кластерного индекса _Consts_ByKey_B и на всю таблицу. |
При использовании платформы 8.3 без режима совместимости с 8.2 в управляемом режиме блокировок чтение в транзакции и без транзакции неблокирующее, вследствие использования уровня изоляции Read Commited Snapshot (RCS).
В автоматическом режиме блокировок в 8.3 без режима совместимости с 8.2 будут наложены аналогичные S и RangeS-S-блокировки, как и в 8.2 (см. иллюстрации выше).
В случае, если транзакции не используются, чтение в 8.2.13, 8.2.14 и 8.3 будет неблокирующее.
Таким образом, можно заполнить следующую таблицу-ответ на вопрос билета 1:
Действие 1 | Действие 2 | 8.2.13 | 8.2.14 | 8.3 |
Запись Конст1 | Запись Конст2 | — | + | + |
Чтение Конст1 | Запись Конст2 | — | + | + |
Чтение Конст1 | Чтение Конст2 | + | + | + |
Вопрос 1.2
Ответ на вопрос зависит от режима управления блокировкой в конфигурации и от версии платформы.
В случае автоматического режима и платформы 8.2 будет следующая картина:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Процедура КнопкаВыполнитьНажатие(Кнопка) НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый); Номенклатура = ВыбраннаяНоменклатура.ПолучитьОбъект(); // // метод ПолучитьОбъект() установил следующие блокировки: // 1. Разделяемая S-блокировка на запись кластерного индекса PK___Referen__AC8ED0C499C42AD1. // 2. Блокировки намерения IS на страницу кластерного индекса PK___Referen__AC8ED0C499C42AD1, // на всю таблицу _Reference7, // 3. Блокировки намерения IS на страницу кластерного индекса _Reference7_VT1763_IntKeyInd табличной части и на всю таблицу табличной части. Номенклатура.Наименование = Номенклатура.Наименование + “ измененное наименование”; Номенклатура.Записать(); // метод Записать() преобразовал разделяемые блокировки в исключительные. В итоге установлены: // 1. Исключительная X-блокировка на запись некластерного индекса _Reference7_ParentDescr_RLSR. // 2. Исключительная X-блокировка на запись дополнительного некластерного индекса с учётом иерархии _Reference7_ByParentField24_RLSSRL (создан вручную для одного из реквизитов). // 3. Исключительная X-блокировка на запись некластерного индекса _Reference7_Descr_SR. // 4. Исключительная X-блокировка на запись кластерного индекса PK___Referen__AC8ED0C499C42AD1. // 5. Исключительная X-блокировка запись дополнительного некластерного индекса без учёта иерархии _Reference7_ByField25_SSRL (создан вручную для одного из реквизитов). // 6. Блокировки намерения IX на страницу индексов _Reference7_ParentDescr_RLSR, _Reference7_ByParentField24_RLSSRL, _Reference7_Descr_SR, PK___Referen__AC8ED0C499C42AD1, _Reference7_ByField25_SSRL. // 7. Блокировка намерения IX на всю таблицу справочника. // 8. Разделяемая блокировка намерения IS на страницу индекса табличной части _Reference7_VT1763_IntKeyInd. // 9. Разделяемая блокировка намерения IS на таблицу табличной части. ЗафиксироватьТранзакцию(); // метод ЗафиксироватьТранзакцию() снял все установленные блокировки. КонецПроцедуры |

Поведение платформы в автоматическом режиме на платформе 8.3 будет аналогично.
Рассмотрим управляемый режим блокировок.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Процедура КнопкаВыполнитьНажатие(Кнопка) НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый); Номенклатура = ВыбраннаяНоменклатура.ПолучитьОбъект(); // // метод ПолучитьОбъект() в процессе чтения строк данных устанавливал // S-блокировку на считываемые строки и сразу же после чтения их снимал. Номенклатура.Наименование = Номенклатура.Наименование + “ измененное наименование”; Номенклатура.Записать(); // метод Записать() установил исключительную X-блокировку на запись следующих индексов: // _Reference7_ByParentField24_RLSSRL - дополнительный индекс по полю и иерархии, // _Reference7_ParentDescr_RLSR - индекс по иерархии и наименованию, // _Reference7_ByField25_SSRL - дополнителный индекс по полю, // _Reference7_Descr_SR - индекс по наименованию, // PK___Referen__AC8ED0C4A906DB30 - кластерный индекс, // а также блокировки намерения IX на страницы этих же индексов и IX-блокировку на всю таблицу справочника. // Также установлена управляемая блокировка 1С на пространство Reference7.REFLOCK. ЗафиксироватьТранзакцию(); // метод ЗафиксироватьТранзакцию() снял все установленные блокировки СУБД и управляемую блокировку 1С КонецПроцедуры |
Также в управляемом режиме при выполнении метода Записать() установилась управляемая блокировка на пространство Reference7.REFLOCK .
Данный код может привести к взаимоблокировке с видом «повышение уровня изоляции ресурса» вследствие следующих действий:
Если две параллельные транзакции в автоматическом режиме установят разделяемую S-блокировку на один и тот же ресурс, выполнив запрос в транзакции (методом ПолучитьОбъект()), то в последствии каждая транзакция будет вынуждена ждать другую для установки исключительной X-блокировки. Менеджер блокировок СУБД распознает это и возникнет взаимоблокировка.
Взаимоблокировка СУБД вследствие повышения уровня изоляции ресурса
Для решения проблемы взаимоблокировки можно пойти несколькими путями:
- Получать ссылку на объект номенклатуры запросом с опцией для ИЗМЕНЕНИЯ. Например, так:
12345678910111213141516171819НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);Запрос = Новый Запрос("ВЫБРАТЬ| СправочникТовары.Ссылка|ИЗ| Справочник.Товары КАК СправочникТовары|ГДЕ| СправочникТовары.Ссылка = &Ссылка||ДЛЯ ИЗМЕНЕНИЯ");Запрос.УстановитьПараметр("Ссылка",СправочникСсылка);Результат = Запрос.Выполнить(); // здесь будет наложена U-блокировка на запись кластерного индекса справочникаВыборка = Результат.Выбрать();Выборка.Следующий();Номенклатура = Выборка.Ссылка.ПолучитьОбъект();Номенклатура.Наименование = Номенклатура.Наименование + " измененное наименование";Номенклатура.Записать();ЗафиксироватьТранзакцию(); - Перевести конфигурацию в управляемый режим блокировок. В этом случае разделяемая S-блокировка будет снята в процессе выполнения запроса после чтения строк данных (для 8.2) и не будет установлена вообще (для 8.3).
- Использовать методы объектной блокировки (для интерактивного режима). В этом случае метод Заблокировать() вызовет исключение, если данный объект уже заблокирован другим пользователем:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый); Номенклатура = СправочникСсылка.ПолучитьОбъект(); Попытка Номенклатура.Заблокировать(); Номенклатура.Наименование = Номенклатура.Наименование + " измененное наименование"; Номенклатура.Записать(); ЗафиксироватьТранзакцию(); Исключение Сообщить(ОписаниеОшибки()); ОтменитьТранзакцию(); КонецПопытки; |
Вопрос 1.3
Особенностями автоматического режима управления блокировкой данных является следующее:
- При чтении запросом с опцией для ИЗМЕНЕНИЯ пустой таблицы будет заблокирована RangeS-U-блокировкой пустая запись индекса. любая другая запись будет «соседней» для пустой записью и не может быть вставлена в таблицу.
- Блокировка на соседних записях в регистре также вызвана особенностью Range-блокировок, которые не только блокируют считанный/записанный диапазон, но и ещё одну строку ниже этого диапазона.
Для решения указанных проблем требуется перевод конфигурации в управляемый режим, в котором нет Range-блокировок.
Для этого нужно выполнить следующие действия:
- Сделать копию рабочей базы.
- В копии рабочей базы установить свойство «Режим управления блокировкой» в значение «Управляемый».
- Найти в коде конфигурации все места, где выполняется чтение итогов регистра и последующая запись в этот регистр.
- Использовать в этих местах исключительную управляемую блокировку 1С на записываемые данные или использовать новую методику проведения (сначала записывать данные, потом контролировать итоги по регистру). В последнем случае рассмотреть возможность использования разделения итогов и опции БлокироватьДляИзменения набора записей.
- Сделать резервную копию рабочей базы.
- Объединить конфигурации.
- Провести тестирование.