Интеграция систем на платформе «1С:Предприятие 8» с внешними базами данных — стандартная задача для современных корпоративных информационных систем. Для этих целей разработчики чаще всего используют встроенный механизм Внешних источников данных (ВИД). Это удобный инструмент, позволяющий работать с таблицами сторонних СУБД (MS SQL Server, PostgreSQL, Oracle, MySQL и др.) практически так же, как и с собственными объектами конфигурации 1С. В качестве альтернативного инструмента для передачи информации можно использовать подсистему выгрузки данных во внешнюю базу SQL.
Однако при активной эксплуатации интеграции разработчики нередко сталкиваются с крайне неприятным симптомом: подключение к внешней базе вроде бы проходит успешно, но первый же запрос на выборку или запись данных «подвисает» на неопределенный срок. При этом прямое подключение к СУБД под той же учетной записью (например, через SQL Server Management Studio) работает быстро и стабильно. Проанализируем, почему так происходит, и разберем по шагам, как решить эту проблему раз и навсегда.
В процессе обсуждения технической проблемы на форуме выяснилось, что первопричиной бесконечного зависания запросов к внешнему источнику данных является накопление открытых транзакций на стороне целевой СУБД. Давайте детально рассмотрим внутренние механизмы взаимодействия платформы 1С и SQL-сервера через ODBC-драйвер.
rphost). Если соединение не разорвано принудительно, оно остается активным на сервере баз данных и переходит в спящий режим (статус sleeping в MS SQL Server).SELECT). Этот режим называется неявными транзакциями.РазорватьСоединение(), транзакция остается открытой. Когда таких «спящих» транзакций накапливается критическое количество, СУБД начинает испытывать дефицит ресурсов, новые запросы выстраиваются в очередь ожидания блокировок (Lock Wait), и система полностью зависает.Именно поэтому простая вставка вызова метода РазорватьСоединение() решает проблему: физический сеанс на стороне SQL корректно завершается, все связанные с ним незафиксированные транзакции автоматически откатываются, а занятые блокировки освобождаются.
Очень часто разработчики ищут свойство «Таймаут» непосредственно в свойствах объекта метаданных ВнешнийИсточникДанных в Конфигураторе 1С. К сожалению, встроенного свойства для ограничения времени ожидания ответа СУБД там нет. Время ожидания соединения и выполнения запросов настраивается исключительно через параметры строки подключения ODBC-драйвера. При необходимости проверить текущие параметры подключения можно использовать обработку для получения строки соединения с внешним источником данных.
Рассмотрим подробнее ключевые параметры строки подключения, которые необходимо добавлять при динамическом формировании строки соединения:
remote query timeout в MS SQL Server).Пример формирования строки подключения к MS SQL Server с установленным таймаутом соединения в 15 секунд:
СтрокаПодключения = "DRIVER={SQL Server};SERVER=MySqlServer;DATABASE=ExternalDB;UID=1c_user;PWD=SecretPassword;Connect Timeout=15;";
ВнешнийИсточник = ВнешниеИсточникиДанных.ИмяВашегоИсточника;
ВнешнийИсточник.УстановитьОбщуюСтрокуПодключения(СтрокаПодключения);
Если из внешнего источника данных вам требуется только читать информацию (например, для построения отчетов или синхронизации справочников), зависания из-за блокировок можно предотвратить изменением уровня изоляции транзакций.
Выясним, как это сделать:
ВнешнийИсточникДанных.При использовании этого режима запросы на чтение из 1С не будут запрашивать блокировки совместного доступа к таблицам сторонней СУБД. Наш запрос выполнится мгновенно, даже если в этот момент внешнее приложение производит массовую запись в эту же таблицу. Единственный минус такого подхода — гипотетическая возможность прочитать транзакционные (еще не зафиксированные другими пользователями) данные. В большинстве интеграционных задач этим риском можно пренебречь.
Если же «грязное чтение» недопустимо по соображениям бизнес-логики, рекомендуется активировать на стороне целевой СУБД MS SQL режим версионирования строк — Read Committed Snapshot Isolation (RCSI). В этом случае читающие запросы 1С будут бесконфликтно читать данные из базы данных tempdb, не пересекаясь с пишущими транзакциями.
Если через внешний источник данных вы выполняете не только чтение, но и изменение (запись) информации, критически важно оборачивать процесс в явную транзакцию 1С с обязательным откатом в случае возникновения непредвиденных ошибок СУБД.
Проанализируем и внедрим в практику следующий отказоустойчивый шаблон написания кода:
ВнешнийИсточник = ВнешниеИсточникиДанных.ИмяВашегоИсточника;
// 1. Устанавливаем соединение с внешней базой
Попытка
ВнешнийИсточник.УстановитьСоединение();
Исключение
ЗаписьЖурналаРегистрации("Интеграция.Подключение",
УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось подключиться к внешнему источнику: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// 2. Начинаем явную транзакцию на стороне внешней СУБД
ВнешнийИсточник.НачатьТранзакцию();
Попытка
// Выполняем операции записи данных
НоваяЗапись = ВнешнийИсточник.Таблицы.ИмяТаблицы.СоздатьОбъект();
НоваяЗапись.КодОбъекта = "12345";
НоваяЗапись.Наименование = "Тестовая запись через ВИД";
НоваяЗапись.Записать();
// Если все операции прошли успешно, фиксируем изменения в СУБД
ВнешнийИсточник.ЗафиксироватьТранзакцию();
Исключение
// В случае ЛЮБОЙ ошибки обязательно производим отмену транзакции,
// чтобы не оставить блокировки активными в памяти SQL-сервера
Если ВнешнийИсточник.ТранзакцияАктивна() Тогда
ВнешнийИсточник.ОтменитьТранзакцию();
КонецЕсли;
ЗаписьЖурналаРегистрации("Интеграция.Запись",
УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка при записи данных: " + ОписаниеОшибки());
КонецПопытки;
// 3. Явно разрываем физическое соединение с базой данных
ВнешнийИсточник.РазовратьСоединение();
Важное примечание: Если проигнорировать вызов метода ОтменитьТранзакцию() внутри блока Исключение, транзакция на стороне SQL-сервера останется незавершенной («зависшей»). Это гарантированно приведет к блокировке работы с таблицами для всех последующих сеансов как со стороны 1С, так и со стороны других информационных систем.
При отладке интеграций через ВИД разработчики часто сталкиваются с ситуацией: в файловом режиме на компьютере программиста все работает идеально, но после переноса конфигурации на сервер 1С запросы начинают зависать или выдавать ошибки прав доступа.
Выясним причину этой проблемы:
Trusted_Connection=yes или Integrated Security=SSPI), то при запуске кода на сервере 1С подключение к внешней СУБД происходит от имени учетной записи операционной системы Windows, под которой запущена сама служба сервера 1С (обычно это системный пользователь USR1CV8).USR1CV8 отсутствуют сетевые права доступа к внешнему серверу SQL или к конкретной базе данных, операционная система может запустить процесс долгого сетевого согласования прав (Handshake), из-за чего поток выполнения кода 1С зависнет на длительное время, не выдавая явную ошибку СУБД.Для исключения подобных ситуаций при серверной работе рекомендуется использовать явную авторизацию СУБД (SQL Server Authentication) с указанием логина и пароля пользователя базы данных в строке подключения, либо предварительно предоставить полные сетевые права и права СУБД для учетной записи службы USR1CV8.