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




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2024-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 не будет опубликован. Обязательные поля помечены *