Блокировки
Полное руководство по блокировкам
Основные понятия и назначение блокировок
Что такое блокировка?
Блокировка данных — механизм, обеспечивающий конкурен тный доступ пользователей к информационной базе и целостность данных при одновременных изменениях. Она предотвращает конфликты, когда несколько пользователей пытаются изменить одни и те же данные.
Простой аналог: Продавец блокирует яблоко для покупателя, пока тот отсчитывает деньги. Другие покупатели не могут выбрать это яблоко до завершения операции.
Проблемы, которые решают блокировки:
-
Потерянное изменение — когда изменения одной транзакции перезаписываются другой
// Транзакция A: // Транзакция B:
Остаток = 100 Остаток = 100
Остаток = Остаток - 10 = 90 Остаток = Остаток - 20 = 80
Записать(90) Записать(80) // Затерло 90! -
"Грязное" чтение — чтение незафиксированных данных
// Транзакция A: // Транзакция B параллельно:
ИзменитьСумму(1000 → 2000) Сумма = ПрочитатьСумму() // =2000!
ОтменитьТранзакциюА() // Работа с некорректным значением -
Неповторяемое чтение — разные результаты при повторном чтении тех же данных
// Транзакция A: // Транзакция B:
Сумма = Прочитать() // =1000 // Параллельно:
Изменить(1000 → 2000)
Сумма = Прочитать() // =2000! -
Чтение фантомов — появление новых данных между чтениями (актуально для необъектных сущностей, например, регистры сведений и накопления)
// Транзакция A (регистр сведений, упрощенный пример):
ВсегоЗаписей = КоличествоЗаписей() // =100
// Транзакция Б добавляет новую запись
ДобавитьЗаписьВРегистр()
ВсегоЗаписей = КоличествоЗаписей() // =101!
Типы блокировок в 1С
1. Объектные блокировки (для работы с объектами: справочники, документы)
- 1.1. Пессимистические блокировки
- Явные (через метод
Заблокировать()илиЗаблокироватьДанныеДляРедактирования()) - Неявные (в форме) (автоматически при редактировании в форме)
- Явные (через метод
- 1.2. Оптимистические блокировки (проверяют версию при записи)
2. Транзакционные блокировки (для работы с данными в транзакциях)
- 2.1. Автоматические блокировки (управляются СУБД, используются высокие уровни изоляции)
- 2.2. Управляемые блокировки (управляются разработчиком через 1С, исп ользуются низкие уровни изоляции)
- Явные (создаются через объект БлокировкаДанных)
- Неявные (устанавливаются платформой автоматически)
Краткая характеристика:
- Объектные блокировки: Не позволяют интерактивно изменить двум пользователям один объект (элемент справочника или документ)
- Транзакционные блокировки: Позволяют программно оперировать актуальными данными при выполнении движений по регистрам
Объектные блокировки
Пессимистическая блокировка
Назн ачение: Запрещает изменение объекта другими сеансами или данным сеансом до снятия блокировки.
Как работает:
- Автоматически устанавливается при редактировании объекта в форме
- Вручную можно использовать через
Заблокировать()илиЗаблокироватьДанныеДляРедактирования()
Важно: Факт блокировки не мешает изменению объекта — для защиты нужно всегда пытаться заблокировать объект перед изменением.
Пример кода:
ФайлОбъект = ДанныеФайла.Ссылка.ПолучитьОбъект();
Попытка
ФайлОбъект.Заблокировать();
// Изменяем объект
ФайлОбъект.Записать();
Исключение
// Обработка ошибки блокировки
КонецПопытки;
Оптимистическая блокировка
Назначение: Проверяет, не изменился ли объект с момента его чтения.
Принцип работы:
- При вызове
ПолучитьОбъект()платформа считывает версию данных объекта (ВерсияДанных) - Если другой сеанс параллельно изменит и запишет этот же объект, его версия изменится
- При попытке записи объекта из первого сеанса происходит сравнение версий
- Ес ли версии не совпадают — возникает ошибка "Нарушение целостности чтения объекта базы данных из-за параллельного изменения объекта другим сеансом"
Транзакционные блокировки: режимы и уровни изоляции
Уровень изоляции транзакций — это параметр СУБД, который определяет степень защиты данных от конфликтов при одновременной работе нескольких транзакций. Он представляет собой компромисс между:
- Целостностью данных (предсказуемость, непротиворечивость)
- Параллельностью работы (скорость, производительность)
Два режима работы
| Аспект | Автоматический режим | Управляемый режим |
|---|---|---|
| Уровень изоляции СУБД | Repeatable Read или Serializable | Read Committed |
| Управление блокировками | Система полагается на механизмы СУБД | Разработчик сам управляет блокировками |
| Производительность | Ниже (избыточные блокировки) | Выше (точные блокировки) |
| Рекомендация | Для обратной совместимости | Для современных конфигураций (рекомендуется) |
Сравнение уровней изоляции:
| Проблема / Уровень | READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE |
|---|---|---|---|---|
| Грязное чтение | ✅ Возможно | ❌ Запрещено | ❌ Запрещено | ❌ Запрещено |
| Неповторяемое чтение | ✅ Возможно | ✅ Возможно | ❌ Запрещено | ❌ Запрещено |
| Фантомы | ✅ Возможно | ✅ Возможно | ✅ Возможно | ❌ Запрещено |
| Параллельность | Высокая | Средняя | Низкая | Очень низкая |
Read Committed Snapshot (RCSI): Режим версионирования, поддерживается в PostgreSQL, Oracle и MS SQL (с 8.3). Нет ожиданий на блокировках при чтении т.к если другая транзакция пишет данные, ваш запрос не ждет, а читает "старый снимок" данных, которые были до начала записи. Рекомендуется включать для 8.2 или 8.3 в режиме совместимости с 8.2.
Сравнение Read Committed vs Read Committed Snapshot
| Критерий | Read Committed | Read Committed Snapshot |
|---|---|---|
| 🛡️ Проблемы, которые решает | Только "грязное чтение" | "Грязное чтение" + ожидания на блокировках |
| 📖 Как работает чтение | Читает последние за фиксированные данные | Читает "старый снимок" данных на момент начала запроса |
| ⏳ Поведение при конфликте | Если данные пишутся другой транзакцией → ждет (блокируется) | Если данные пишутся другой транзакцией → не ждет, читает предыдущую версию |
| 📈 Параллельность | Средняя (чтение может блокироваться на запись) | Высокая (чтение и запись не блокируют друг друга) |
| 💾 Использование памяти | Низкое (не хранит старые версии) | Высокое (хранит старые версии строк в tempdb до конца транзакции) |
| ⚙️ Включение в MS SQL | Уровень по умолчанию | Нужно включать отдельно: ALTER DATABASE SET READ_COMMITTED_SNAPSHOT ON |
Простая аналогия:
| Read Committed | Read 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);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
// Обработка ошибки
КонецПопытки;
Когда ответственное чтение НЕ требуется?
- Получение данных для отображения: Динамические списки, поиск, отчеты
- Работа с условно-постоянными данными: Константы, учетная политика
- Монопольный режим: Обновление базы, первоначальное заполнение
- Персональные/уникальные данные: Данные в разрезе пользователей, мобильное приложение
Выбор типа блокировки
Основные правила:
- Читаете и потом изменяете те же данные → Исключительная блокировка
- Читаете данные (чтобы они не менялись), но изменяете другие → Разделяемая блокировка на читаемые + исключительная на изменяемые
- Только чтение без последующих изменений → Блокировка не нужна