Урок по треку Разработка на 1С 5 мин

Транзакции и блокировки

Транзакции, управляемые блокировки, БлокировкаДанных, взаимоблокировки и ошибки в транзакции.

Ошибки «превышено время ожидания блокировки» и продажа одного товара дважды обычно происходят из-за непонимания блокировок. Это любимая тема собесов middle и senior.

Транзакции

Транзакция выполняется целиком или не выполняется. Неявно транзакция открывается при записи объекта: внутри неё выполняются ПередЗаписью, ПриЗаписи, ОбработкаПроведения и запись наборов. Явно:

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

Стандарт 1С: начинать до Попытка, в Исключение сначала отменять, потом логировать и пробрасывать.

Вложенных транзакций нет. Платформа считает уровень вложенности, но транзакция одна. ОтменитьТранзакцию на любом уровне отменяет всё, и дальнейшие операции с базой падают с ошибкой «в данной транзакции уже происходили ошибки».

Транзакции должны быть короткими: никаких вопросов пользователю, HTTP-запросов и тяжёлых вычислений внутри.

Режимы блокировок

  • Автоматический: блокировки СУБД, устаревший.
  • Управляемый: блокировки на сервере 1С по данным. Используется в современных конфигурациях.
  • Автоматический и управляемый: переходный.

Управляемые блокировки

Ставятся менеджером блокировок сервера 1С на пространство (например, регистр) и значения полей. Живут до конца транзакции.

  • Исключительная: несовместима ни с какой другой на те же данные.
  • Разделяемая: совместима с разделяемыми, несовместима с исключительной.

Платформа сама ставит исключительную блокировку на записываемые данные. Чтение запросом не блокирует. Поэтому в схеме «прочитать, проверить, записать» разработчик ставит блокировку явно, до чтения:

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

Заблокировать() вне транзакции вызывает ошибку. Предложение запроса ДЛЯ ИЗМЕНЕНИЯ в управляемом режиме игнорируется.

Ожидание и взаимоблокировки

Если данные заняты, транзакция ждёт. После таймаута (по умолчанию около 20 секунд) пользователь получает «Конфликт блокировок... превышено максимальное время ожидания». Виновник почти всегда длинная транзакция в другом сеансе.

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

  • сразу ставить исключительную блокировку на то, что будете менять;
  • брать блокировки в одном порядке;
  • блокировать только нужные значения, а не всю таблицу.

Диагностика

Технологический журнал: события TLOCK (установка), TTIMEOUT (таймаут ожидания), TDEADLOCK (взаимоблокировка) с контекстом модуля и строки. Для мониторинга ЦУП из КИП.

Частые ошибки

  • Чтение остатков без блокировки перед списанием.
  • НачатьТранзакцию внутри Попытка, Исключение без ОтменитьТранзакцию.
  • Вопрос пользователю или HTTP-запрос в транзакции.
  • Обмен данными одной огромной транзакцией в рабочее время.

Что спросят на собесе

  • Чем исключительная блокировка отличается от разделяемой?
  • Почему в управляемом режиме нужно блокировать перед чтением?
  • Что будет при ОтменитьТранзакцию во вложенной процедуре?
  • Как найти, кто держит блокировку?
  • Как избежать взаимоблокировок?

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.