Как победить блокировки транзакций в 1С 7.7 TIS DBF при большом количестве пользователей?

Программист 1С v7.7 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

Работа в многопользовательской среде на платформе 1С:Предприятие 7.7 с использованием формата DBF часто превращается в борьбу с блокировками. Особенно остро это проявляется в конфигурациях типа «Торговля и Склад» (ТиС) при количестве пользователей более 20–30. Основная проблема заключается в том, что движок базы данных блокирует таблицы целиком, а не построчно. В данной статье мы подробно разберем, как диагностировать причины блокировок и какие программные методы позволяют минимизировать простои системы.

Анализ природы блокировок: основные «узкие места»

Разберем, какие таблицы чаще всего становятся причиной остановки работы 40 пользователей. Проанализируем типичные ситуации:

  1. 1SJOURN (Журнал документов): Любая попытка создать новый документ, записать или провести его вызывает блокировку этой таблицы. Поскольку номер документа часто зависит от максимального номера в журнале, система блокирует всю таблицу, чтобы избежать дублей.
  2. 1SDNLOCK (Блокировка номеров): Используется при генерации новых номеров. Если пользователь «завис» на открытой форме нового документа, это может блокировать создание документов другими участниками.
  3. 1SUPDTS (Таблица изменений УРИБ): Если используется распределенная база данных (УРИБ), запись любого изменения сопровождается фиксацией в этой таблице, что создает дополнительную конкуренцию.
  4. Регистры (RA* и RG*): Блокируются при проведении документов. Чем тяжелее модуль проведения и чем больше в нем расчетов (особенно задним числом), тем дольше висит блокировка.

Шаг 1: Установка времени ожидания захвата в ноль

Рассмотрим стандартное поведение: когда таблица заблокирована, другие пользователи ждут (по умолчанию до 30 секунд), и их интерфейс «замерзает». Мы рекомендуем установить время ожидания в 0. Это позволит системе мгновенно выводить сообщение о блокировке, не «подвешивая» сессию пользователя. Разберем код, который можно вставить в процедуру ПриНачалеРаботыСистемы, чтобы автоматически патчить файл конфигурации пользователя 1Cv7.CFG:


Функция УстановитьВ0ВремяОжидания()
    ВремяОжиданияЗахватаБазы = Константа.ВремяОжиданияЗахватаБазы; // Предположим, там 0
    ЛокВэйт = 0;
    Попытка
        МойТекст1С = СоздатьОбъект("Текст");
        МойТекст1С.Открыть(КаталогПользователя() + "1Cv7.CFG");
        Для НомерСтроки = 1 По МойТекст1С.КоличествоСтрок() Цикл
            СтрокаТекста = МойТекст1С.ПолучитьСтроку(НомерСтроки);
            Если Найти(СтрокаТекста, "LockWaitTime") > 0 Тогда
                Если Найти(СтрокаТекста, Симв(34) + "LockWaitTime" + Симв(34) + "," + Симв(34) + "0" + Симв(34)) = 0 Тогда
                    МойТекст1С.ЗаменитьСтроку(НомерСтроки, "{" + Симв(34) + "LockWaitTime" + Симв(34) + "," + Симв(34) + "0" + Симв(34) + "}}");
                    ЛокВэйт = -1;
                    Прервать;
                Иначе
                    ЛокВэйт = 1;
                КонецЕсли;
            КонецЕсли;
        КонецЦикла;
        Если ЛокВэйт = -1 Тогда
            МойТекст1С.Записать(КаталогПользователя() + "1Cv7.CFG");
            Предупреждение("Настройки обновлены. Пожалуйста, перезапустите 1С.", 5);
            Возврат 0;
        КонецЕсли;
    Исключение
    КонецПопытки;
    Возврат 1;
КонецФункции

Важный момент: При установке ожидания в ноль критически важно использовать правильные библиотеки. Мы рекомендуем использовать Kernel33.dll (для решения проблемы файлов > 1 ГБ) или Kernel37.dll, которая также оптимизирует нагрузку на процессор при ожидании блокировок.

Шаг 2: Использование «Попытки» и пауз при программном создании объектов

Если в вашей конфигурации одни документы создают другие (например, «Реализация» создает «Счет-фактуру»), это часто приводит к ошибкам захвата таблицы 1SJOURN. Рассмотрим ситуацию, когда мы пытаемся создать документ в цикле, делая паузы, чтобы «проскочить» между блокировками других пользователей. Для реализации паузы (Sleep) лучше использовать внешние компоненты, например 1C++ или FormEx.


Процедура СоздатьДокументСПовтором()
    Сервис = СоздатьОбъект("Сервис"); // Объект FormEx или 1C++
    Успешно = 0;
    Для ПопыткаНомер = 1 По 20 Цикл
        Попытка
            Док = СоздатьОбъект("Документ.СчетФактура");
            Док.Новый();
            // Заполнение реквизитов...
            Док.Записать();
            Успешно = 1;
            Прервать;
        Исключение
            // Если таблица занята, ждем 0.5 секунды и пробуем снова
            Сервис.Sleep(500); 
        КонецПопытки;
    КонецЦикла;
    Если Успешно = 0 Тогда
        Сообщить("Не удалось создать документ из-за длительных блокировок. Попробуйте позже.");
    КонецЕсли;
КонецПроцедуры

Шаг 3: Эмуляция режима просмотра («Лупа») для предотвращения блокировок

Проанализируем интересную особенность 1С 7.7: открытие существующего документа обычным способом накладывает блокировку на его запись в журнале, даже если вы просто смотрите на него. Однако открытие через «Лупу» (только просмотр) блокировку не вызывает. Мы можем перехватить выбор строки в журнале и принудительно открывать документы в режиме только чтения для пользователей, которым не нужны правки.


Процедура ПриВыбореСтроки() 
    СтатусВозврата(0);
    // Проверяем права или условия
    Если (ТекущийДокумент.Вид() = "ПоступлениеТМЦ") И (НуженТолькоПросмотр = 1) Тогда
        // Третий параметр "1" открывает форму в режиме только просмотра
        ОткрытьФорму(ТекущийДокумент, , 1); 
    Иначе
        ОткрытьФорму(ТекущийДокумент);
    КонецЕсли;
КонецПроцедуры

Шаг 4: Асинхронное выполнение операций через внешние события

Часто блокировки возникают, когда внутри транзакции проведения одного документа выполняются тяжелые действия с другими объектами. Рассмотрим пример: при проведении накладной нужно автоматически создать и напечатать Счет-Фактуру. Чтобы не удлинять транзакцию накладной, мы можем использовать генерацию внешнего события (требуется FormEx). Процесс будет выглядеть так: накладная проводится быстро, закрывает транзакцию, а затем система «сама себе» посылает команду создать СФ.

В модуле документа:


Процедура ОбработкаПроведения()
    // Основная логика проведения
    ...
    // Генерируем событие для асинхронного создания СФ
    Сервис = СоздатьОбъект("Сервис");
    Сервис.ВнешнееСобытие("ГенераторСФ", "Создать", ЗначениеВСтрокуВнутр(ТекущийДокумент()));
КонецПроцедуры

В глобальном модуле:


Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
    Если Источник = "ГенераторСФ" Тогда
        ДокОснование = ЗначениеИзСтрокиВнутр(Данные);
        // Здесь создаем СФ вне транзакции проведения накладной
        глСоздатьСчетФактуру(ДокОснование);
    КонецЕсли;
КонецПроцедуры

Шаг 5: Оптимизация итогов и борьба с размером файлов

Выясним причину замедления проведения документов: если файлы регистров (особенно RA328.DBF — партии) приближаются к 2 ГБ, 1С начинает работать крайне нестабильно. Это критический порог для DBF.

Рассмотрим способы ускорения расчетов:

Теоретическая справка по транзакциям в 1С 7.7

Для глубокого понимания ситуации проанализируем положения работы движка:

  1. Транзакции в 7.7 DBF накладывают блокировку на всю таблицу, а не на отдельные строки.
  2. Вложенные транзакции в 1С 7.7 — это фикция. Реально работает только транзакция самого верхнего уровня.
  3. Чтение вне транзакции не блокирует таблицу, но если таблица уже заблокирована кем-то на запись, чтение может перейти в режим ожидания.
  4. Операции Новый() и Записать() всегда неявно открывают транзакцию.

Подведем итог: чтобы победить блокировки на 40 пользователях в DBF, необходимо максимально сократить время нахождения системы внутри транзакции. Выносите расчеты цен, поиск партий и заполнение сложных структур данных до момента вызова Записать() или Провести(). Используйте кеширование констант и эмуляцию режима чтения для журналов. Это позволит вашей системе работать стабильно даже при высоких нагрузках.

← На главную