Skip to main content

Блокировки

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

Основные понятия и назначение блокировок

Что такое блокировка?

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

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

Проблемы, которые решают блокировки:

  1. Потерянное изменение — когда изменения одной транзакции перезаписываются другой

    // Транзакция A:                  // Транзакция B:
    Остаток = 100 Остаток = 100
    Остаток = Остаток - 10 = 90 Остаток = Остаток - 20 = 80
    Записать(90) Записать(80) // Затерло 90!
  2. "Грязное" чтение — чтение незафиксированных данных

    // Транзакция A:                  // Транзакция B параллельно:
    ИзменитьСумму(1000 → 2000) Сумма = ПрочитатьСумму() // =2000!
    ОтменитьТранзакциюА() // Работа с некорректным значением
  3. Неповторяемое чтение — разные результаты при повторном чтении тех же данных

    // Транзакция A:                    // Транзакция B:
    Сумма = Прочитать() // =1000 // Параллельно:
    Изменить(1000 → 2000)
    Сумма = Прочитать() // =2000!
  4. Чтение фантомов — появление новых данных между чтениями (актуально для необъектных сущностей, например, регистры сведений и накопления)

    // Транзакция A (регистр сведений, упрощенный пример):
    ВсегоЗаписей = КоличествоЗаписей() // =100

    // Транзакция Б добавляет новую запись
    ДобавитьЗаписьВРегистр()

    ВсегоЗаписей = КоличествоЗаписей() // =101!

Типы блокировок в 1С

1. Объектные блокировки (для работы с объектами: справочники, документы)

  • 1.1. Пессимистические блокировки
    • Явные (через метод Заблокировать() или ЗаблокироватьДанныеДляРедактирования())
    • Неявные (в форме) (автоматически при редактировании в форме)
  • 1.2. Оптимистические блокировки (проверяют версию при записи)

2. Транзакционные блокировки (для работы с данными в транзакциях)

  • 2.1. Автоматические блокировки (управляются СУБД, используются высокие уровни изоляции)
  • 2.2. Управляемые блокировки (управляются разработчиком через 1С, используются низкие уровни изоляции)
    • Явные (создаются через объект БлокировкаДанных)
    • Неявные (устанавливаются платформой автоматически)

Краткая характеристика:

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

Объектные блокировки

Пессимистическая блокировка

Назначение: Запрещает изменение объекта другими сеансами или данным сеансом до снятия блокировки.

Как работает:

  • Автоматически устанавливается при редактировании объекта в форме
  • Вручную можно использовать через Заблокировать() или ЗаблокироватьДанныеДляРедактирования()

Важно: Факт блокировки не мешает изменению объекта — для защиты нужно всегда пытаться заблокировать объект перед изменением.

Пример кода:

ФайлОбъект = ДанныеФайла.Ссылка.ПолучитьОбъект();
Попытка
ФайлОбъект.Заблокировать();
// Изменяем объект
ФайлОбъект.Записать();
Исключение
// Обработка ошибки блокировки
КонецПопытки;

Оптимистическая блокировка

Назначение: Проверяет, не изменился ли объект с момента его чтения.

Принцип работы:

  • При вызове ПолучитьОбъект() платформа считывает версию данных объекта (ВерсияДанных)
  • Если другой сеанс параллельно изменит и запишет этот же объект, его версия изменится
  • При попытке записи объекта из первого сеанса происходит сравнение версий
  • Если версии не совпадают — возникает ошибка "Нарушение целостности чтения объекта базы данных из-за параллельного изменения объекта другим сеансом"

Транзакционные блокировки: режимы и уровни изоляции

Уровень изоляции транзакций — это параметр СУБД, который определяет степень защиты данных от конфликтов при одновременной работе нескольких транзакций. Он представляет собой компромисс между:

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

Два режима работы

АспектАвтоматический режимУправляемый режим
Уровень изоляции СУБДRepeatable Read или SerializableRead Committed
Управление блокировкамиСистема полагается на механизмы СУБДРазработчик сам управляет блокировками
ПроизводительностьНиже (избыточные блокировки)Выше (точные блокировки)
РекомендацияДля обратной совместимостиДля современных конфигураций (рекомендуется)

Сравнение уровней изоляции:

Проблема / УровеньREAD UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLE
Грязное чтение✅ Возможно❌ Запрещено❌ Запрещено❌ Запрещено
Неповторяемое чтение✅ Возможно✅ Возможно❌ Запрещено❌ Запрещено
Фантомы✅ Возможно✅ Возможно✅ Возможно❌ Запрещено
ПараллельностьВысокаяСредняяНизкаяОчень низкая

Read Committed Snapshot (RCSI): Режим версионирования, поддерживается в PostgreSQL, Oracle и MS SQL (с 8.3). Нет ожиданий на блокировках при чтении т.к если другая транзакция пишет данные, ваш запрос не ждет, а читает "старый снимок" данных, которые были до начала записи. Рекомендуется включать для 8.2 или 8.3 в режиме совместимости с 8.2.

Сравнение Read Committed vs Read Committed Snapshot

КритерийRead CommittedRead Committed Snapshot
🛡️ Проблемы, которые решаетТолько "грязное чтение""Грязное чтение" + ожидания на блокировках
📖 Как работает чтениеЧитает последние зафиксированные данныеЧитает "старый снимок" данных на момент начала запроса
⏳ Поведение при конфликтеЕсли данные пишутся другой транзакцией → ждет (блокируется)Если данные пишутся другой транзакцией → не ждет, читает предыдущую версию
📈 ПараллельностьСредняя (чтение может блокироваться на запись)Высокая (чтение и запись не блокируют друг друга)
💾 Использование памятиНизкое (не хранит старые версии)Высокое (хранит старые версии строк в tempdb до конца транзакции)
⚙️ Включение в MS SQLУровень по умолчаниюНужно включать отдельно: ALTER DATABASE SET READ_COMMITTED_SNAPSHOT ON

Простая аналогия:

Read CommittedRead Committed Snapshot
Библиотека с одной книгой: Читатель ждет, пока другой читатель закончит писать заметки на полях.Библиотека с ксероксом: Читатель сразу получает копию книги в том виде, в котором она была до начала написания заметок.

Настройка режима в конфигурации

Свойство конфигурации "Режим управления блокировкой данных":

  • Автоматический — все объекты в автоматическом режиме
  • Управляемый — все объекты в управляемом режиме (по умолчанию для новой конфигурации)
  • Автоматический и управляемый — объекты работают в режиме, указанном в их свойствах

Работа с блокировками из кода

Объект БлокировкаДанных — основной инструмент

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

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

Таблица совместимости:

РазделяемаяИсключительная
Разделяемая
Исключительная

Когда какой режим использовать:

  • Разделяемый: Данные нельзя изменить до конца транзакции (другие могут читать)
  • Исключительный: Данные нельзя ни изменить, ни прочитать с разделяемой блокировкой

Особенности чтения разных объектов

Сравнение блокировок при чтении в 8.2 и 8.3:

Аспект / Платформа1С:Предприятие 8.2 (и 8.3 в режиме совместимости)1С:Предприятие 8.3 (без режима совместимости)Рекомендация
Запрос.Выполнить()Ставится S-блокировка (разделяемая) в СУБДБлокировка на чтение отсутствует8.3 выигрывает в параллельности
НаборЗаписей.Прочитать()Управляемая разделяемая блокировка до конца транзакцииАналогично 8.2Для чистого чтения используйте Запрос!
Объектное чтение (справочники, документы)Управляемые блокировки не устанавливаютсяАналогично 8.2Для чтения безопаснее, чем НаборЗаписей

📌 Ключевая проблема: НаборЗаписей.Прочитать() всегда устанавливает управляемую разделяемую блокировку, которая держится до конца транзакции!

Ответственное чтение данных

Что такое ответственное чтение?

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

Примеры:

  • Чтение остатков при проведении документа для формирования движений
  • Получение данных для последующей целостной передачи в другую систему
  • Групповая обработка в обновлениях ИБ

Как обеспечить ответственное чтение?

❌ Неправильный подход (риск потери данных):

КоличествоЗаметок = ЗапросНаЧтениеЗаметок().Выполнить();
// МЕЖДУ ЧТЕНИЕМ И ЗАПИСЬЮ ДРУГОЙ СЕАНС МОЖЕТ ИЗМЕНИТЬ ДАННЫЕ!
ЗаписатьНовуюЗаметку(КоличествоЗаметок + 1);

✅ Правильный подход (с блокировками):

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

// 2. Читаем и изменяем данные
КоличествоЗаметок = ЗапросНаЧтениеЗаметок().Выполнить();
ЗаписатьНовуюЗаметку(КоличествоЗаметок + 1);

ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
// Обработка ошибки
КонецПопытки;

Когда ответственное чтение НЕ требуется?

  1. Получение данных для отображения: Динамические списки, поиск, отчеты
  2. Работа с условно-постоянными данными: Константы, учетная политика
  3. Монопольный режим: Обновление базы, первоначальное заполнение
  4. Персональные/уникальные данные: Данные в разрезе пользователей, мобильное приложение

Выбор типа блокировки

Основные правила:

  1. Читаете и потом изменяете те же данныеИсключительная блокировка
  2. Читаете данные (чтобы они не менялись), но изменяете другиеРазделяемая блокировка на читаемые + исключительная на изменяемые
  3. Только чтение без последующих измененийБлокировка не нужна

Оптимизация и практические рекомендации

Ключевые принципы оптимизации

  1. Минимизация времени удержания блокировок

    ❌ Плохо (долгая блокировка):

    НачатьТранзакцию();
    Блокировка(); // Ранняя блокировка
    // ... долгие расчеты (10 секунд) ...
    Записать();
    ЗафиксироватьТранзакцию();

    ✅ Хорошо (короткая блокировка):

    // Расчеты БЕЗ транзакции (10 секунд)
    НачатьТранзакцию();
    Блокировка(); // Блокировка в конце
    Записать();
    ЗафиксироватьТранзакцию(); // Блокировка всего 0.1 секунды
  2. Правильный выбор метода доступа к данным

    • Для чтения: Всегда используйте Запрос вместо НаборЗаписей.Прочитать()
    • Для изменения: Используйте объектную модель с блокировками
  3. Использование разделителя итогов

Включите галочку "Разрешить разделение итогов" для регистров без контроля остатков. Это позволяет параллельно обновлять итоги по одному набору измерений.

Эскалация блокировок

Что это: Когда блокируется не строка, а вся таблица или пространство.

Пороги эскалации:

  • MS SQL Server: >5 000 блокировок одной инструкцией
  • 1С:Предприятие 8.2: ~20 000 блокировок на одно пространство
  • 1С:Предприятие 8.3: ~100 000 блокировок на одно пространство

Решение: Делите большие операции на пакеты (по 1000-2000 записей).

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

Два механизма контроля остатков

АспектСтарый механизм (OLD)Новый механизм (NEW)
Принцип работы1. Контроль остатков (запрос) 2. Запись движений1. Запись движений 2. Проверка на отрицательные остатки
ИспользованиеБухгалтерия 3.0, некоторые алгоритмы УТ 11, КА 2, ЕРП 2УТ 11, КА 2, ЕРП 2 (основной механизм)
Преимущества1. Выше скорость проведения 2. Нет перезаписи пустых наборов 3. Нет необходимости в предварительной блокировке
НедостаткиТребует блокировки данных при чтении (снижает параллельность)Если для проведения нужны данные из регистров, блокировка при чтении все равно требуется

Вывод: Используйте новый механизм (NEW), если проведение документа не требует предварительных запросов к данным.

Стратегии блокировок для разных режимов

Для управляемого режима с NEW механизмом:

// Ключевая настройка для регистров с разделением итогов!
НаборЗаписей.БлокироватьДляИзменения = Истина;

Эта настройка временно отключает разделение итогов для данного набора, предотвращая конфликты. Устанавливается обычно перед записью.

Частые проблемы и их решения

Взаимоблокировки (Deadlock)

Симптом: Две транзакции ждут друг друга.

Причины:

  • Недостаточный уровень изоляции

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

    Если две транзакции одновременно удерживают S-блокировки на одних и тех же ресурсах и запрашивают X-блокировки для их изменения, возникает взаимоблокировка.

  • Неоптимальный порядок блокировок

    Пример: Два документа — «Поступление товаров» и «Реализация товаров» — при проведении обращаются к одним и тем же виртуальным таблицам регистров, но порядок вызова методов записи различен:

    // Поступление товаров
    // 1. 🔒 Сначала блокируются ОстаткиНаСкладах
    ОстаткиНаСкладах.Записать();

    // 2. Потом пробуем блокировать ОстаткиОрганизаций, но уже заблокировано реализацией, ожидаем...
    ОстаткиОрганизаций.Записать();
    // Реализация товаров
    // 1. 🔒 Сначала блокируются ОстаткиОрганизаций
    ОстаткиОрганизаций.Записать();

    // 2. Потом пробуем блокировать ОстаткиНаСкладах, но уже заблокировано поступлением, ожидаем...
    ОстаткиНаСкладах.Записать();

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

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

Решение:

  • Блокировка в транзакции должна изначально осуществляться с максимально необходимым уровнем
  • Устанавливать блокировки в одинаковом порядке
  • Делать транзакции короткими

Ожидания на блокировках

Причины:

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

Решение:

  • Заменять НаборЗаписей на Запросы
  • Оптимизировать запросы
  • Включать разделитель итогов

Сводная таблица решений

ПроблемаСутьРешение
Грязное чтениеЧитаем незафиксированные данныеS-блокировка на время чтения
Потеря измененийПерезапись изменений другого процессаX-блокировка на всю транзакцию
Неповторяемое чтениеДанные меняются между чтениями в одной транзакцииS-блокировка на всю транзакцию
Чтение фантомовПоявление новых строк между запросамиБлокировка диапазона

Ответы на ключевые вопросы

Базовые вопросы:

  1. Какие типы блокировок существуют в 1С? → Объектные и транзакционные
  2. В чем разница между пессимистической и оптимистической блокировкой? → Пессимистическая блокирует сразу, оптимистическая проверяет при записи
  3. Что такое ответственное чтение? → Чтение, после которого происходят изменения или принимаются решения

Практические вопросы:

  1. Когда нужно использовать ЗаблокироватьДанныеДляРедактирования()? → Перед изменением объекта из кода
  2. Почему НаборЗаписей.Прочитать() может вызывать проблемы? → Ставит управляемую блокировку до конца транзакции
  3. Как перевести конфигурацию на управляемые блокировки? → Установить режим "Управляемый" и настроить блокировки в коде

Глубинные вопросы:

  1. В чем разница между автоматическим и управляемым режимом? → Автоматический использует высокие уровни изоляции СУБД, управляемый — низкие с ручным управлением
  2. Как избежать взаимоблокировок при проведении документов? → Правильный порядок блокировок, короткие транзакции, использование БлокироватьДляИзменения
  3. Что такое эскалация блокировок и как с ней бороться? → Укрупнение блокировки при большом количестве; делить операции на пакеты

Вопросы на понимание:

  1. Когда НЕ нужно устанавливать блокировки? → При чтении для отображения, работе с константами, в монопольном режиме
  2. Какой уровень изоляции используется в управляемом режиме и почему?Read Committed для большей параллельности
  3. В чем преимущество нового механизма контроля остатков (NEW)? → Не требует предварительной блокировки, выше скорость

Ключевые выводы

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

  2. Используйте управляемый режим для современных конфигураций — он дает большую гибкость и производительность

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

  4. Избегайте НаборЗаписей.Прочитать() для чтения — используйте Запросы

  5. Делайте транзакции короткими — выносите расчеты за пределы транзакции

  6. Понимайте разницу между механизмами контроля остатков OLD и NEW

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

  8. Помните об эскалации при работе с большими объемами данных

Материалы