среда, 17 июля 2013 г.

pconnect() в разумных целях

О сколько нам открытий чудных
Готовят просвещенья дух
И опыт, сын ошибок трудных,
И гений, парадоксов друг,
И случай, бог изобретатель.
А.С.Пушкин

Этим постом я ввожу целых два новых тега в свой блогооборот: "опыт" и "рабзаметки". Посты с тегом "опыт" будут содержать некоторые знания, полученные мной эмпирически и,как мне кажется, могут оказаться полезными мне самому в дальнейшем (вспомнить, подсмотреть) и кому-нибудь из читателей. Они не претендуют на аксиомы и довольно субъективны, но проверены опытным путём и, стало быть, в каком-то высоком проценте случаев работают.
Тег "рабзаметки" я ввёл для идентификации заметок, сделанных в ходе моей рабочей деятельности.
Под катом — первая ласточка, комбинирующая оба этих тега. Возможно, кому-нибудь будет полезно.
Не так давно мне пришлось ковыряться в чужом коде скрипта, который делал буквально следующее:
  • подключался к двум разным и физически удалённым базам данных;
  • проверял, есть ли данные из базы-донора в базе-приёмнике (структурно они одинаковы);
  • если нет — добавлял эти данные, если есть — обновлял имеющиеся.
Всё просто — обычная миграция данных.
Однако, несмотря на всю простоту, скрипт упорно запихивал данные из базы-донора в саму себя, игнорируя явное указание подключения к другой базе для INSERT/UPDATE.Таким образом, создавалась куча дубликатов своих же записей, а в целевой базе изменений не было.Хотя скрипт упорно трудился, пыхтел, то есть какой-то процесс всё же происходил.
Убедившись ещё раз в том, что я запускаю запросы на нужных подключениях, я решил приглядеться к тому, как инициализированы сами эти подключения.
Схема скрипта выглядела примерно так:
   //конфиг с настройками подключения к базе-приёмнику
   include(config.php);
   ...

   //подключение к базе-приёмнику
   $conn = ADONewConnection("mysql");
   $conn->PConnect('host','user','pass','db');
   
   ...
   //подключение к базе-донору
   $conn2 = ADONewConnection("mysql");
   $conn2->PConnect('host_2','user_2','pass_2','db_2');

   //выбираем данные из базы-донора
   $res = $conn2->Execute("SELECT ...");
   list($var1,$var2,...) = $res->FetchRow();

   ...

   //вставляем выбранные данные в базу-приёмник
   $res = $conn->Execute("INSERT ...");
   ...
В результате — данные запихиваются снова в базу-донора.
Фишка оказалась в следующем: используя две функции pconnect в одном скрипте, мы тем самым допускаем перекрытие постоянных соединений между собой. Поскольку подключение к базе-донору было последним, то оно, почему-то и использовалось для выполнения запроса, хотя явно было указано использовать подключение к базе-приёмнику.
Проблема решилась буквально удалением одного символа:
$conn2->Connect('host_2','user_2','pass_2','db_2');
Использование функции connect позволило скрипту выполнить то,что ему было указано без конфликта с предыдущим соединением.
Читать дальше......