Как обработать выборку из MySQL и сохранить картинки (BLOB) в 1С 8.3

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При интеграции 1С с внешней базой данных MySQL посредством ADO часто возникает необходимость не только считать строковые и числовые поля, но и извлечь двоичные данные — например, изображения, хранящиеся в полях типа BLOB или LONGBLOB.

В этой статье мы разберем, как правильно обходить объект ADODB.Recordset, выгружать полученную выборку в объект 1С ТаблицаЗначений и сохранять графические файлы на диск с помощью COM-объекта ADODB.Stream.

Анализ проблемы и особенностей работы с ADO и MySQL

Проанализируем базовые сложности, с которыми сталкиваются разработчики при прямом подключении к MySQL из 1С:

  1. Чтение значений полей: Доступ к значениям колонок текущей записи в ADODB.Recordset осуществляется через коллекцию RS.Fields("ИмяПоля").Value или по индексу колонки.
  2. Тип данных BLOB в 1С: При чтении двоичного поля MySQL платформа 1С получает объект типа COMSafeArray. Попытка записать его напрямую в файл или обработать стандартными функциями 1С без предварительного преобразования вызывает ошибку.
  3. Медленная работа запроса: Если курсор ADO работает в серверном режиме по умолчанию (CursorLocation = 2 / adUseServer), при вызове MoveNext() происходит регулярный сетевой обмен с СУБД. При наличии объёмных BLOB-полей это существенно замедляет выборку.

Решение: Пошаговый алгоритм обработки выборки и сохранения картинок

Рассмотрим рабочее решение. Для эффективного сохранения каждого изображения создается отдельный поток ADODB.Stream, либо один поток циклически открывается, заполняется данными методом Write(), сохраняется в файл методом SaveToFile() и закрывается на каждой итерации выборки.

Разберем по шагам реализацию этого процесса:

  1. Создаем и настраиваем COM-объекты ADODB.Command и ADODB.Recordset.
  2. Устанавливаем клиентский курсор (CursorLocation = 3), чтобы вся выборка загружалась в память разом. Это ускорит обработку.
  3. Формируем динамическую ТаблицуЗначений в 1С, создавая колонки с именами, соответствующими полям MySQL.
  4. В цикле Пока НЕ RS.EOF Цикл считываем значение каждого поля. При обнаружении BLOB-поля с картинкой передаем COMSafeArray в объект ADODB.Stream и записываем файл на диск.

Посмотрим на полный пример кода на языке 1С:


ТекстЗапроса = "select barcode, date_ins, date_upd, image from photo WHERE date_ins >= STR_TO_DATE('01.10.2017','%d.%m.%Y') AND date_ins <= STR_TO_DATE('06.10.2017','%d.%m.%Y')";

// Настраиваем команду ADO
Command = Новый COMОбъект("ADODB.Command");
Command.ActiveConnection = АДОСоединение;
Command.CommandText = ТекстЗапроса;
Command.CommandType = 1; // adCmdText

// Настраиваем набор записей
RS = Новый COMОбъект("ADODB.Recordset");
RS.ActiveConnection = АДОСоединение;
RS.CursorLocation = 3; // adUseClient (клиентский курсор ускоряет передачу данных)
RS.CursorType = 3;     // adOpenStatic

// Выполняем запрос
RS = Command.Execute();

// Создаем ТаблицуЗначений для хранения результатов в 1С
РезультатЗапроса = Новый ТаблицаЗначений;
КоличествоПолей = RS.Fields.Count;

Для НомерКолонки = 0 По КоличествоПолей - 1 Цикл
    РезультатЗапроса.Колонки.Добавить(RS.Fields.Item(НомерКолонки).Name);
КонецЦикла;

// Инициализируем Stream для сохранения двоичных файлов
StreamЗапись = Новый COMОбъект("ADODB.Stream");
StreamЗапись.Type = 1; // 1 = adTypeBinary
StreamЗапись.Mode = 3; // 3 = adModeReadWrite

// Обходим полученные записи
Пока НЕ RS.EOF Цикл
    НоваяСтрока = РезультатЗапроса.Добавить();
    
    Для НомерКолонки = 0 По КоличествоПолей - 1 Цикл 
        ИмяПоля = RS.Fields.Item(НомерКолонки).Name;
        Значение = RS.Fields(ИмяПоля).Value;
        
        Если ИмяПоля = "image" И Значение <> Неопределено Тогда
            StreamЗапись.Open();  
            StreamЗапись.Write(Значение); 
            
            ИмяФайла = RS.Fields("barcode").Value; 
            ПутьКФайлу = КаталогВременныхФайлов() + ИмяФайла + ".jpg"; 
            
            // 2 = adSaveCreateOverWrite (перезаписывать существующий файл)
            StreamЗапись.SaveToFile(ПутьКФайлу, 2); 
            StreamЗапись.Close();  
        КонецЕсли;
        
        НоваяСтрока[ИмяПоля] = Значение;
    КонецЦикла;
    
    RS.MoveNext();
КонецЦикла;    

RS.Close();

Важные ограничения и рекомендации по оптимизации

Выясним причину возможных сбоев при эксплуатации подобного решения на серверных базах и различных операционных системах:

  1. Зависимость от ОС Windows: COM-объекты ADODB.Connection, ADODB.Recordset и ADODB.Stream являются технологиями Microsoft. На сервере 1С под управлением Linux данный код работать не будет.
  2. Разрядность процесса (32/64 bit): Если код выполняется на 64-разрядном сервере 1С или в 64-битном клиенте, в операционной системе должен быть установлен 64-разрядный ODBC-драйвер MySQL. Использование 32-битного драйвера из 64-битного процесса вызовет ошибку подключения.
  3. Альтернатива без COM (Внешние источники данных): Если необходима кроссплатформенность, рекомендуется использовать штатный механизм 1С «Внешние источники данных». Он позволяет подключаться к MySQL напрямую через стандартный язык запросов 1С и автоматически преобразует поля BLOB в объект ДвоичныеДанные.
← На главную