Разыменования в коде (и прочее) — что при этом делает СУБД




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2026-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

28 Comments

  1. tormozit

    Рекомендую изучение подобной темы начинать с описания работы кэшей на ИТС:

    — Объектный кэш

    — Транзакционный кэш

    — Кэш представлений ссылок

    Также полезно техножурналом смотреть сначала запросы модели базы данных (SDBL), т.к. в них меньше «мусора» и лучше видна логика работы платформы.

    Reply ↓
  2. ImHunter

    (1) Это все понятно:) Но мое стремление было — увидеть своими глазами, что делает СУБД. Ибо документация может и не отражать всех особенностей.

    Reply ↓
  3. w.r.

    Как бы известно, что если по ссылке получаешь реквизит, например:

    ЗаказСсылка.Номер

    то из СУБД считывается целиком объект со всеми реквизитами и табличными частями

    поэтому, если нужно считать 1 или несколько реквизитов из сложного объекта, типа документа, то рекомендуют делать это через Запрос

    https://its.1c.ru/db/metod8dev/content/2717/hdoc

    Reply ↓
  4. tormozit

    Своими глазами ты например не увидел проверку в СУБД версии данных при обращении к объекту, находящемуся в объектном кэше.

    Reply ↓
  5. ImHunter

    (4) Видел вполне себе… Все-пре-все наблюдения — не было целью описать.

    Reply ↓
  6. tormozit

    (5) Ну статья же вроде обещает рассказать «что при этом делает СУБД». Считаю, что без упоминания запроса проверки версии данных статья лишена важного элемента.

    Reply ↓
  7. ImHunter

    (6) Принято. Подумаю, как дополнить. Но с другой стороны, такими проверками особо не порулить.

    Reply ↓
  8. Glebis

    А какие поля опрашиваются при вызове метода «Представление» в запросе?

    Reply ↓
  9. ImHunter

    (8) Точно! Хотел ведь глянуть итоговый такой запрос. К концу сегодня (28.02) докину пример.

    Reply ↓
  10. Darklight

    Про обращение к константе добавь

    Про разделители напиши

    Про то, как изменятся запрос при применении RLS тоже важно было бы упомянуть

    Reply ↓
  11. Darklight

    (8)

    (6)

    пардон не туда нажал

    Reply ↓
  12. Darklight

    (9)Не забудьте заодно и про метод «ПРЕДСТАВЛЕНИЕССЫЛКИ» и про свойство «.Представление»

    Reply ↓
  13. strek_ivan

    В БСП с целью оптимизации обращения с СУБД как раз и используется

    ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита, ВыбратьРазрешенные = Ложь).

    Не пренебрегайте этой функцией и, тем самым, сократите время выполнения кода.

    Reply ↓
  14. ImHunter

    Дописал про ПРЕДСТАВЛЕНИЕССЫЛКИ / ПРЕДСТАВЛЕНИЕ.

    Reply ↓
  15. user710334_koshil.v

    Попытался. В самописную конфу вставил функцию из БСП.

    Задача: приСозданииНаСервере() в реквизит «кладовщик» прописать значение реквизита «сотрудник» справочника «Пользователи». Ссылка на пользователя находится в параметре сеанса «ТекущийПользователь»:

    p.s. неудачно скриншоты получились.

    Там где обращение тупо кладовщикВыдачи = ПараметрыСеанса.ТекущийПользователь.Сотрудник время 0,003309, а там где КладовщикВыдачи = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ПараметрыСеанса.ТекущийПользователь,»Сотрудник»); время 0,039332 — ровно на порядок. Может пример неудачный?

    Reply ↓
  16. VVi3ard

    Статья как уже заметил (1) не достаточно объективная.

    Что решит обычный разработчик прочитав ее?

    «Получать через точку не выгодно».

    А на самом деле зачастую выгоднее получать через «.» особенно если объект это какой то НСИ который редко меняется.

    Т.к. с высокой долей вероятности значение всех полей уже есть в кэше и чтение из БД не потребует чтения из базы.

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

    Так например обращение к реквизиту формы через «.» с вероятностью 90% приведет к чтению кэша а не к получению данных из ИБ.

    Думаю что для полноты статьи нужно провести эксперименты с учетом кэширования.

    Reply ↓
  17. acanta

    Кэширование повышает риск недостоверности данных. оптимизируется не скорость, а надежность.

    Reply ↓
  18. vasilev2015

    Здравствуйте !

    я не верю, что Сообщить(Строка(Валюта)); не считывает весь объект. Вы запускали эту команду первой, или Вы запускаете ее, когда объект помещен в кэш ?

    Reply ↓
  19. ImHunter

    (18) Я писал в публикации, что при нескольких разыменованиях используется кеширование.

    А вообще, я вопрос не понял. Во что вы таки не верите?

    Reply ↓
  20. vasilev2015

    (19) я считаю, что Сообщить(Строка(Валюта)); должен считать весь объект, если раньше не было объектного чтения для переменной «Валюта». Profiler мне пока недоступен.

    Reply ↓
  21. ImHunter

    (20) Ну не знаю:) Запросы из профайлера, вам, видимо, не аргумент. Но и ваш аргумент «не верю» — слабоват. Поэтому либо верьте, либо не верьте, либо проверяйте тех.журналом.

    Reply ↓
  22. vasilev2015

    (21) запросы из Профайлера для меня нормальный аргумент. Я просто спрашиваю: было ли перед командой Сообщить(Строка(Валюта)) объектное чтение переменной Валюта или нет ?

    Reply ↓
  23. ImHunter

    (22) Нет, конечно. Ведь основная цель была не в исследовании кеширования.

    Reply ↓
  24. dock

    Хотелось бы такой же проверки для более новых версий платформы (8.3.14 — 8.3.15)

    Могу ошибаться, но вроде как обещали изменить поведение при чтении стандартных реквизитов (номер, дата и т.д.)

    Reply ↓
  25. ImHunter

    (24) Про изменение поведения тоже краем уха слышал. Для себя спланировал, что как выйдет следующий релиз 14 платформы (после 1779), так и займусь.

    Reply ↓
  26. buganov

    (16) Уот так уот, оказывается методами БСП невыгодно получать реквизит. Нонсенс!

    Давайте поможем Даше получить оптимальнее контрагента из ссылки на заказ.

    Вариант 1. Через точку. При этом считаются все реквизиты, табличные части из СУБД. В лучшем случае из кеша. Но в кеш то надо еще получить!

    Вариант 2. Управляемый. С помощью запроса за 3 мс получить значение нужного реквизита без мусора. Гарантировано всегда быстро.

    Ах да, писатели типовых ведь сплошь стажеры, придумали фигню, лучше бы всю базу в кеш затолкали, а чего, быстро же будет!

    Reply ↓
  27. gubanoff

    (18) для случая Сообщить(Валюта) точно не считывает — в этом случае платформа понимает, что нужно получить только представление объекта, оно кэшируется. А вот для случая преобразования в строку — это вопрос, но он по сути не имеет смысла, т.к. этот код в любом случае методическая ошибка.

    Reply ↓
  28. ImHunter

    (24) Планирую заняться подобными исследованиями на 8.3.16.1063.

    Кому что интересно — пишите.

    Пока что в ближайших планах — проверить вычитывание ТЧ и стандартные реквизиты (код, номер, дата).

    Прошу не писать про кеширование — по максимуму буду избегать его использование.

    Reply ↓

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *