Перенос PHP-приложений с MySQL на DB2: Часть 3. Преобразование PHP-кода

Опыт миграции интранет-приложения IBM

Узнайте, зачем переносить PHP-приложение на DB2®, как спланировать и выполнить миграцию, как поддерживать ее и как справиться с потенциальными рисками, на примере опыта миграции интранет-приложения IBM. В этой серии статей, состоящей из четырех частей, рассматривается уроки успешной миграции с MySQL на DB2 критически важного PHP-приложения, которое используют 4000 пользователей из разных стран мира для управления содержимым сайта ibm.com. В третьей части рассматриваются действия по преобразованию PHP-кода.

Дэниел Крук, инженер-программист, IBM

Дэниел Крук (Daniel Krook) – сертифицированный специалист (IBM/Open Group Master Certified IT Specialist), проживающий в Нью-Йорке. Имеет более чем 10-летний опыт разработки Web-приложений, а в настоящее время занимается созданием облачной инфраструктуры для IBM с использованием Java EE, DB2, REST и мобильных технологий. Имеет сертификаты по PHP, Java EE, BlackBerry, DB2 и Solaris. Пишет статьи по PHP для IBM developerWorks и является соавтором документа IBM Redbook "Разработка PHP-приложений для IBM Data Servers".



Янь Ли Му, ИТ-архитектор, IBM

Янь Ли Му (Yan Li Mu) – ИТ-архитектор, работающий в Даляне (КНР). Занимается созданием Web-приложений более 8 лет, уделяя основное внимание технологиям Java EE, PHP и разработке баз данных.



Марк Ньюскейбл, старший ИТ-архитектор, IBM

Марк Ньюскейбл (Mark Nusekabel) – сертифицированный специалист (IBM/Open Group Master Certified IT Architect), проживающий в Тампа-Бэй, Флорида. Занимается информационными технологиями более 20 лет; в настоящее время проектирует инструментальные средства с использованием JavaScript, PHP, Java и DB2. Имеет сертификаты по решениям для электронного бизнеса, а также по Java и XML.



08.06.2012

Введение в серию статей

В настоящее время MySQL является самым распространенным сервером баз данных, используемым с языком программирования PHP для создания динамичных Web-приложений. Другая популярная база данных - DB2, которая хорошо поддерживается PHP и имеет неоспоримые преимущества перед MySQL, которые делают ее идеальным выбором для многих приложений.

Эта серия статей рассказывает о том, почему целесообразно перенести PHP-приложение на DB2, как подготовиться к миграции, как выполнить ее, как поддерживать ее и как справиться с потенциальными рисками, на примере опыта, приобретенного авторами ходе недавно проведенной миграции. Приводится много примеров исходного кода и конфигураций, а также ссылок на ресурсы, которые помогут безболезненно выполнить перенос приложения.

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

В этой серии, состоящей из четырех статей, рассматриваются уроки успешной миграции с MySQL на DB2 работающего критически важного PHP-приложения, которое используют 4000 пользователей из разных стран мира для управления содержимым сайта ibm.com.

  • В первой части рассматриваются действия по подготовке миграции.
  • Во второй части рассматриваются действия по миграции базы данных.
  • В третьей части рассматриваются действия по преобразованию PHP-кода.
  • В четвертой части рассматриваются действия по развертыванию и поддержке приложения.

Что вы узнаете

Цель данной серии статей – дать информацию о том, что нужно для переноса PHP-приложения с MySQL на DB2, какие имеются дополнительные ресурсы и как группа разработчиков IBM выполнила эту задачу в начале 2010 года.

Если вы изучали вопрос миграции с MySQL на DB2, вы, вероятно, уже оценили преимущества DB2, принимая во внимание информацию о продукте, тесты производительности, функции, описанные в документации по DB2, и сравнения в документах IBM Redbook®, включая "Руководство по переходу с MySQL на DB2" (см. раздел Ресурсы).

Возможно, вам также известно, что DB2 Express-C является бесплатным, полнофункциональным сервером реляционных баз данных, который можно легко установить или опробовать на платформах IBM Smart Business Development and Test Cloud или Amazon EC2 (ссылки приведены в разделе Ресурсы).

Данная серия статей описывает конкретный пример реальной миграции, успешно выполненной в 2010 году для интенсивно эксплуатируемого PHP-приложения, используемого компанией IBM в повседневной работе по управлению контентом, публикуемым в многочисленных разделах Web-сайта ibm.com.

После прочтения данной серии статей вы сможете выполнить аналогичную миграцию, определить сроки ее выполнения и зависимости элементов работ, оценить потенциальные риски и узнать, где найти помощь для каждого этапа проекта. Все это позволит вам еще увереннее сделать выбор в пользу сервера DB2 и его использования для PHP-приложений, которые в настоящее время работают на MySQL.

Что здесь не рассматривается

Цель данной серии статей – поделиться с читателями опытом, полученным IBM в процессе внутренней миграции с MySQL на DB2, и предоставить информацию об имеющихся ресурсах для выполнения аналогичной задачи. Она не является всеобъемлющим руководством по миграции, охватывающим все возможные сценарии.

Чтобы определить соответствующий вашим требованиям подход, обратитесь к "Руководству по переходу с MySQL на DB2" или обратитесь в отдел Software Migration Project Office (SMPO) за бесплатной оценкой миграции. Ссылки приведены в разделе Ресурсы.


Введение в миграцию кода

В данной статье рассматриваются пять основных видов работ по переводу исходного кода PHP-приложения с синтаксиса и драйверов MySQL на синтаксис и драйверы DB2. Место этих действий в общем плане процесса миграции рассматривалось в первой части данной серии статей .

Этап 1. Первый этап миграции исходного кода
  • Убедитесь, что данная конфигурация PHP поддерживает DB2.
  • Модифицируйте отдельные SQL-выражения для поддержки синтаксиса DB2.
  • При необходимости создайте аналоги функций MySQL при помощи определяемых пользователем функций DB2.
  • При необходимости перенесите логику из SQL в PHP.
Этап 2. Второй этап миграции исходного кода
  • Проанализируйте необходимость изменений для поддержки соответствующих уровней изоляции.
  • Сгруппируйте запросы в логические блоки для достижения лучшей целостности данных и повышения производительности.
Этап 3. Первоначальное тестирование вариантов использования заинтересованными лицами
  • Привлеките заинтересованных лиц к выполнению действий, которые они обычно выполняют на старой системе.
  • Зафиксируйте неудачные тесты, чтобы разработчики могли их проанализировать и внести исправления.
Этап 4. Устранение узких мест и проверка по критериям функциональности
  • Улучшите производительность системы, основываясь на реакции пользователей при проверке функциональности.
  • Сконцентрируйтесь на том, что автоматически может исправить сама DB2, поскольку DB2 – это самое большое проведенное вами изменение.
  • Устраните узкие места PHP, проанализировав загрузку системных ресурсов.
Этап 5. Оценка итогов миграции кода
  • После итеративного выполнения указанных выше этапов работ объявите о завершении преобразования исходного кода.
  • Создайте резервную копию системы и зафиксируйте контрольную точку в системе управления версиями.
  • Оцените уровень готовности к следующей задаче – развертыванию приложения.

Знакомство с вариантами использования существующего примера PHP-приложения PTT

Напоминание

При необходимости обратитесь к разделу Ресурсы, который может быть полезен при проведении миграции. На данном этапе особенно полезными могут оказаться следующие ресурсы:

  • Главы 8 и 10 документа IBM Redbook® "Руководство по переходу с MySQL на DB2".
  • Главы 4 и 6 документа IBM Redbook "Разработка PHP-приложений для серверов данных IBM".
  • Статья developerWorks "Список рекомендованной литературы: разработка приложений с использованием DB2 для Linux, UNIX и Windows".
  • Блог Дэниела Крука о личном опыте другого проекта миграции для независимого поставщика.

Конечно же, важным источником информации является документация по языку программирования PHP и расширению-драйверу DB2.

Другим вариантом осуществления миграции является использование облака. Можно использовать виртуальные образы Amazon EC2 Linux and DB2 AMI или сервис IBM SmartCloud, ранее известный как IBM Development and Test on the IBM Cloud (см. раздел Ресурсы).

Исходный код примера приложения PTT (Project Tracking Tool), рассматриваемого в данной статье, состоит из нескольких сотен PHP-файлов. База исходных кодов содержит библиотеки функций, объектно-ориентированный код, организованный в объекты передачи данных (data transfer object) и manager-классы, а также различные фрагменты HTML-шаблонов и вспомогательных классов, формирующих пользовательский интерфейс.

База данных PTT используется при обработке информации, публикуемой на сайте ibm.com. Более 4000 пользователей со всего мира обращаются к базе данных PTT и изменяют ее посредством Web-интерфейса, реализованного на PHP. В каждый момент времени с системой одновременно работает несколько сотен пользователей.

Этот код развертывается на одном Web-сервере Apache, загружающем mod_php как модуль общего использования.

В нашем примере существующий код модифицирован для работы с новой системой DB2, в основном путем изменения встроенных SQL-запросов. Также немного изменена конфигурация PHP для использования DB2-драйвера и модифицирован код подключения к базе данных. В статье также рассматриваются некоторые улучшения структуры приложения для достижения большей целостности архитектуры модель-представление-контроллер (MVC), направленные на повышение качества и удобства эксплуатации приложения.


Установка ПО преобразования

Для выполнения преобразования исходного кода примера на рабочей станции Windows должны быть установлены следующие компоненты:

Копия исходной базы данных MySQL
Важно иметь копию старой системы, чтобы использовать ее в качестве образца функциональности при проверке каждого изменения кода в новой системе относительно старой. Можно использовать ту же систему, которая была настроена во второй части данной серии статей .
Версия DB2 с драйверами сервера данных, установленная локально или на тестовом сервере
Установите DB2 для создания новой целевой базы данных на рабочей станции. Вообще говоря, она не обязательно должна быть той же версии, которая будет использоваться в дальнейшем, но это желательно для обеспечения полной функциональной совместимости. Для работы с примером данной статьи установите DB2 Enterprise Server Edition Version 9.7.2. Убедитесь, что доступны драйверы сервера базы данных для предоставления необходимых библиотек PHP-клиента. Можно использовать ту же систему, которая была настроена во второй части данной серии статей .
Версия PHP-дистрибутива с расширением ibm_db2 или PDO_IBM (PHP Data Objects)
Загрузите последнюю версию Zend Server и выберите расширение DB2, требующее установки дополнительных пакетов.
Среда разработки, например, Zend Studio или Eclipse PHP Development Tools (PDT)
Для облегчения PHP-разработки используйте соответствующую среду, такую как Zend Studio или Eclipse PHP Development Tools. Поскольку вы поддерживаете PHP-приложение, скорее всего, она у вас уже есть.

Тщательно документируйте принимаемые конфигурационные решения и приобретенный опыт, для того чтобы можно было повторить свои действия при развертывании. Подумайте над целесообразностью сохранения состояния операционной системы Windows в виртуальный образ по завершении основных этапов процесса миграции, чтобы иметь резервные копии конфигураций и основу для последующих улучшений базы данных.

Чтобы сохранить образ конфигурации физической машины, воспользуйтесь бесплатной программой VMware vCenter Converter. В качестве альтернативы можно использовать облако. Можно использовать виртуальные образы Amazon EC2 Linux and DB2 AMI или сервис IBM SmartCloud, ранее известный как IBM Development and Test on the IBM Cloud. Используя виртуальные компьютеры, вы сможете избежать первоначальных затрат на приобретение серверного аппаратного обеспечения и установку операционной системы и DB2, что сэкономит время, ускорит процесс миграции и придаст больше уверенности при проведении экспериментов с конфигурациями, соответствующими вашим требованиям. Ссылки на все эти продукты приведены в разделе Ресурсы.


Этап 1. Первый этап миграции исходного кода

Первым важным шагом в преобразовании кода является настройка новой инфраструктуры PHP и DB2 и изменение способа использования приложением PHP и SQL для доступа к данным. На этом шаге выполняются следующие действия:

Обновление PHP-драйвера и конфигурации

Убедитесь, что текущая конфигурация PHP поддерживает драйвер DB2, настроена на кодировку, соответствующую серверной базе данных, и предоставляет важные диагностические сообщения в виде подробных предупреждений и уведомлений об ошибках.

Чтобы обновить PHP-код для DB2, обычно нужно изменить каждое место в коде, где используются функции расширения ibm_db2 или обновляется строка подключения PDO_IBM, реализующая интерфейс PDO (PHP Data Objects). Если в MySQL-системе в качестве библиотеки для работы с базой данных используется PDO, изменения исходного кода будут минимальны. Потребуется изменить всего лишь одну строку подключения. Но даже если используется процедурное расширение ibm_db2, эта задача не является сложной. Обычно можно заменить в исходном коде все функции, название которых начинаются с mysql_ или mysqli_, на их эквиваленты, начинающиеся с db2_. Таблицы отображения функций и примеры приведены в разделе 6.3 главы 6 документа IBM Redbook "Разработка PHP-приложений для серверов данных IBM" (см. раздел Ресурсы).

Оба метода подключения основаны на использовании DB2-клиента в качестве моста к серверу DB2, поэтому необходимо проверить соответствие конфигурации DB2-клиента настройкам удаленного сервера. В частности, нужно проверить идентичность кодовых страниц на DB2-клиенте и DB2-сервере, иначе вы столкнетесь с проблемами кодировки. Например, выполните команду, приведенную в листинге 1, чтобы установить кодировку DB2-клиента в значение UTF-8, в соответствии с командой CREATE DATABASE в листинге 1 второй части серии.

Листинг 1. Установка кодировки DB2-клиента в значение UTF-8
db2set db2codepage=1208

Для проверки этой настройки на всех рабочих станциях или серверах, на которых установлена клиентская система времени исполнения, выполните команду, приведенную в листинге 2.

Листинг 2. Просмотр переменных конфигурации DB2
db2set -all

Наконец, на время разработки полезно установить перехват и отображение в браузере всех предупреждений и сообщений об ошибках. В файле php.ini модифицируйте параметры, приведенные в листинге 3. Не забудьте настроить их на выдачу менее подробных сообщений при передаче в эксплуатацию. В четвертой части данной серии статей рассматривается пример более подходящего механизма выдачи сообщений об ошибках для использования при развертывании эксплуатационной версии.

Листинг 3. Установка в php.ini параметров управления сообщениями об ошибках
display_errors = On
error_reporting = E_ALL & ~E_NOTICE

Преобразование синтаксиса SQL

Модифицируйте отдельные SQL-выражения, чтобы поддерживался синтаксис DB2, либо измените способ их доступа к данным так, чтобы достичь аналогичного результата. Для большинства приложений именно на этом этапе выполняется основная часть изменений исходного кода и проверочных испытаний. Список синтаксических преобразований приводится в главе 8.1 "Сходства и различия в языке управления данными" документа Redbook "Руководство по переходу с MySQL на DB2". Ниже рассматривается несколько ситуаций, которые имели место в случае нашего приложения.

Поведение группового символа оператора SELECT
Выражения SELECT, использующие групповой символ "звездочка" для выбора конкретных столбцов в дополнение ко всем столбцам нескольких таблиц допустимы в MySQL, но запрещены в DB2. В таких ситуациях добавьте уточняющий префикс в виде названия таблицы (или псевдонима) к групповому символу, укажите каждый столбец из каждой таблицы, который вам нужен, либо просто перечислите все столбцы каждой таблицы с одним групповым символом. В листинге 4 показано, как изменить такие запросы.
Листинг 4. Сравнение допустимых групповых символов столбца и таблицы в MySQL и DB2
-- В MySQL: 
SELECT R.NAME, * 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID;

-- В DB2: 
SELECT R.NAME, U.* 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID;

-- Или
SELECT R.NAME, U.ID, U.NAME, U.ROLE_ID, U.DEPART_ID 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID;
Выражение SELECT, указывающее максимальный размер результата запроса при помощи LIMIT
LIMIT – это нестандартное ключевое слово, допустимое только в MySQL и указывающее максимальное число возвращаемых строк. В DB2 для этих целей используется синтаксис FETCH FIRST n ROWS ONLY. В листинге 5 показано, как переписать запрос для DB2.
Листинг 5. Указание максимального числа возвращаемых из строк в MySQL и DB2
-- В MySQL: 
SELECT * FROM ROLE LIMIT 10;

-- В DB2: 
SELECT * FROM ROLE FETCH FIRST 10 ROWS ONLY;
Оператор GROUP BY
MySQL позволяет использовать оператор GROUP BY без указания названий всех столбцов, не обрабатываемых обобщенной функцией в списке столбцов. Но в DB2 это недопустимо, поскольку результат запроса может в определенной степени быть неоднозначным, что неприемлемо для многих пользователей. В листинге 6 показано, как явно указать столбцы в запросе для DB2.
Листинг 6. Сравнение разрешенного использования GROUP BY в MySQL и DB2
-- В MySQL: 
SELECT R.ID, R.NAME, COUNT(U.ID) AS NUM 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID 
GROUP BY R.ID;
				
-- В DB2: 
SELECT R.ID, MIN(R.NAME), COUNT(U.ID) AS NUM 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID 
GROUP BY R.ID;

-- Или
SELECT R.ID, R.NAME, COUNT(U.ID) AS NUM 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID 
GROUP BY R.ID, R.NAME;

В листинге 6 GROUP BY обрабатывается просто, поскольку оба столбца R.ID и R.NAME являются уникальными ключами данной таблице. В листинге 7 показан другой тип запроса GROUP BY, который нельзя обработать также просто, как запрос в листинге 6.

Листинг 7. Неоднозначный оператор GROUP BY в MySQL, который нужно изменить в DB2
-- В MySQL: 
SELECT R.ID, R.NAME, COUNT(U.ID) AS NUM 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID 
GROUP BY R.NAME;

В данном случае R.ID является уникальным для таблицы, а R.NAME – нет. Если в таблице ROLE имеются повторяющиеся значения R.NAME, вы не сможете заменить R.ID на MIN(R.ID) и добавить R.ID в оператор GROUP BY. Способ преобразования этого SQL-запроса зависит от ожидаемого результата. В листинге 8 приведено несколько вариантов для такой ситуации.

Листинг 8. Запрос GROUP BY, преобразованный для DB2
-- В DB2: 
-- Вариант 1. SQL для результата, аналогичного MySQL: 
SELECT (SELECT RL.ID FROM ROLE RL WHERE RL.NAME = R.NAME FETCH FIRST 1 ROW ONLY) AS ID,
R.NAME, COUNT(U.ID) AS NUM 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID 
GROUP BY R.NAME;
				
-- Вариант 2. Если имя роли то же, считать ее той же ролью. В этом случае 
-- результат несколько отличается от MySQL-версии – в нем нет R.ID:
SELECT R.NAME, COUNT(U.ID) AS NUM 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID 
GROUP BY R.NAME;
				
-- Вариант 3. Если идентификатор роли отличается, считать их разными ролями. 
-- В этом случае результат запроса полностью отличается от результата в
-- MySQL-версии:
SELECT R.ID, R.NAME, COUNT(U.ID) AS NUM 
FROM USER U, ROLE R 
WHERE U.ROLE_ID = R.ID 
GROUP BY R.ID, R.NAME;
REPLACE INTO в MySQL по сравнению с MERGE в DB2
MySQL предоставляет оператор REPLACE INTO. DB2 предоставляет оператор MERGE для аналогичных, но не эквивалентных целей. Для получения эквивалентного результата создайте новую запись или замените существующую, если она имеет такой же первичный ключ или уникальное значение. В листинг 9 показано, как проверить в таблице уникальность значения и обновить или вставить значения.
Листинг 9. Преобразование синтаксиса MySQL REPLACE INTO для DB2
-- В MySQL: 
REPLACE INTO ROLE (ID, NAME, DESCRIPTION)
SELECT ID, NAME, DESCRIPTION 
FROM ROLE_TMP;

-- В DB2: 
MERGE INTO ROLE R
USING (SELECT ID, NAME, DESCRIPTION FROM ROLE_TMP) RT
ON (R.ID = RT.ID)
WHEN MATCHED THEN
UPDATE SET (ID, NAME, DESCRIPTION) = (RT.ID, RT.NAME, RT.DESCRIPTION)
WHEN NOT MATCHED THEN
INSERT (ID, NAME, DESCRIPTION) VALUES (RT.ID, RT.NAME, RT.DESCRIPTION);
Оператор JOIN
При внешнем соединении пары таблиц и одновременном извлечении данных из третьей таблицы укажите в DB2 таблицы, используемые для внешнего соединения, вместе с ключевыми словами JOIN. MySQL позволяет указывать их в любом порядке. В листинге 10 показаны необходимые изменения.
Листинг 10. Сравнение синтаксиса JOIN в MySQL и DB2
-- В MySQL работают оба выражения: 
SELECT * 
FROM USER U, ROLE R 
LEFT JOIN DEPARTMENT D 
ON U.DEPT_ID = D.ID;

-- Или
SELECT * 
FROM ROLE R, USER U 
LEFT JOIN DEPARTMENT D 
ON U.DEPT_ID = D.ID;

-- В DB2 работает только это выражение: 
SELECT * FROM ROLE R, USER U 
LEFT JOIN DEPARTMENT D 
ON U.DEPT_ID = D.ID;
Управляющие символы
В MySQL одинарную кавычку представляет последовательность символов \', но в DB2 одинарная кавычка должна предваряться еще одной кавычкой, т.е. получается '' (две одинарные кавычки). В листинге 11 показан пример управляющей последовательности для строки, использующей одинарную кавычку в качестве апострофа.
Листинг 11. MySQL использует обратную косую черту в качестве управляющего символа перед одинарными кавычками, тогда как DB2 использует вторую одинарную кавычку
-- В MySQL: 
SELECT * FROM ROLE 
WHERE DESCRIPTION = 'It\'s a super admin role';

-- В DB2: 
SELECT * FROM ROLE 
WHERE DESCRIPTION = 'It''s a super admin role';
Проверка выхода из диапазона в DB2
MySQL не проверяет диапазон типа данных в операторе SELECT, а DB2 проверяет. Поэтому SQL-запрос, который в листинге 12 запрашивает информацию за период с 1 по 10 февраля, не работает в DB2, но работает в MySQL.
Листинг 12. MySQL не проверяет диапазон значений по типу данных для операторов WHERE
-- MySQL позволяет указать 30 февраля в качестве границы диапазона 
SELECT * FROM USER 
WHERE BIRTHDAY BETWEEN '1980-02-01' AND '1980-02-30';
INSERT (вставка) в столбец NOT NULL без значения по умолчанию
В MySQL выражение INSERT, не предоставляющее значение для столбца NOT NULL, выполнится успешно. MySQL заполняет значение по умолчанию автоматически, даже если при создании таблицы вы не определяли значение по умолчанию для данного столбца. Но в DB2 необходимо указывать значение для столбцов NOT NULL в выражении INSERT, если значение по умолчанию не было определено. SQL-запросы в листинге 13 демонстрируют различное поведение.
Листинг 13. MySQL и DB2 обрабатывают вставку значений NOT NULL по-разному
-- Работает и в MySQL, и в DB2 
CREATE TABLE TEST1 (ID INTEGER, NAME VARCHAR(20) NOT NULL); 

-- Работает в MySQL, но не работает в DB2
INSERT INTO TEST1 (ID) VALUES(1); 

-- Работает и в MySQL, и в DB2 				
CREATE TABLE TEST2 (ID INTEGER, NAME VARCHAR(20) NOT NULL DEFAULT ''); 

-- Работает и в MySQL, и в DB2
INSERT INTO TEST2 (ID) VALUES(1);

Использование новых режимов совместимости DB2

Хотя синтаксис MySQL можно эмулировать при помощи определяемых пользователем функций, начиная с версии DB2 9.7.2 появился еще один новый вариант - установка одного из режимов совместимости. Информация о разрешении использования синтаксиса LIMIT и OFFSET приведена в блоге Антонио Канджано (Antonio Cangiano).

Преобразование MySQL-функций в аналогичные DB2-функции
Кроме специфичных для MySQL SQL-запросов можно использовать встроенные MySQL-функции. Их можно заменить стандартными SQL-функциями или эквивалентными функциями, имеющимися в DB2. Дополнительная информация приведена в "Руководстве по переходу с MySQL на DB2. Приложение A: отображение встроенных функций и операторов MySQL" (см. раздел Ресурсы).

Если эквивалентной DB2-функции нет, можно переписать SQL-запрос для доступа к данным другим способом. В качестве альтернативы можно эмулировать функцию в DB2 или перенести логику в PHP-код, как описано в следующих разделах.

Создание определяемых пользователем функций для эмуляции функций MySQL

Если для получения эквивалентных MySQL результатов недостаточно просто модифицировать SQL-выражения в соответствии с синтаксисом DB2, можно реализовать обходной путь в виде определяемых пользователем функций в DB2 SQL для эмуляции встроенных MySQL-функций.

В нашем сценарии есть несколько мест, где при переходе на DB2 приходится использовать альтернативные методы. Часть функциональности, например, преобразование дат, можно перенести из MySQL в PHP. Можно также эмулировать функции, создав в DB2 определяемые пользователем функции, соответствующие некоторым функциям, встроенным в MySQL, например, UNIX_TIMESTAMP() и NOW(). В "Руководстве по переходу с MySQL на DB2. Приложение B" (см. раздел Ресурсы) объясняются отличия и даются рекомендации по выполнению изменений. Также могут быть полезными советы Дэниела Крука, основанные на его собственном опыте миграции (см. раздел Ресурсы).

DML базы данных DB2 отличается от MySQL. В данной статье описывается преобразование встроенных SQL-операций из MySQL в DB2. Однако нет необходимости преобразовывать весь синтаксис из MySQL в DB2, особенно для встроенных MySQL-функций. В "Руководстве по переходу с MySQL на DB2. Приложение А: отображение встроенных функций и операторов MySQL" (см. раздел Ресурсы) описано большое количество встроенных функций. Многие из них можно преобразовать в UDF-функции DB2. Решение о том, какие часто используемые встроенные функции преобразовывать, принимаете вы. В нашем сценарии стоит потратить время на использование UDF-функций DB2 для преобразования часто используемых MySQL-функций или регистров. Ниже приведен список MySQL-функций и регистров, которые можно преобразовать.

  • CURRENT_DATE() / CURDATE()
  • DATE_FORMAT()
  • DATEDIFF()
  • FROM_UNIXTIME()
  • NOW()
  • PERIOD_DIFF()
  • TO_DAYS()
  • UNIX_TIMESTAMP()
  • WEEKDAY()
  • YEARWEEK()

К счастью многие из этих функций уже реализованы и свободно доступны для повторного использования; они описаны в статье "Основы DB2: работа с датами и временем" (см. раздел Ресурсы). При использовании DB2 v9.7.2 или более новой версии можно попробовать установить новый вектор совместимости DB2_COMPATIBILITY_VECTOR=MYS.

DB2 облегчает применение UDF-функций, поскольку их можно писать на SQL, не используя язык программирования C, как в случае с MySQL.

В листинге 14 приведен пример UDF-функции, которую можно создать для эмуляции нестандартной, но часто используемой функции MySQL NOW(). Эмуляцию можно использовать в разных местах примера приложения.

Листинг 14. Определение UDF-функции DB2 для эмуляции встроенной MySQL-функции NOW()
CREATE FUNCTION NOW()
	RETURNS TIMESTAMP
	NO EXTERNAL ACTION

	BEGIN ATOMIC
		RETURN SELECT CURRENT TIMESTAMP
		FROM SYSIBM.DUAL;
	END

В "Руководстве по переходу с MySQL на DB2. Приложение В" приведено еще несколько определяемых пользователем функций для эмуляции часто используемых встроенных MySQL-функций (см. раздел Ресурсы).

Перенос логики из SQL в PHP при необходимости

Могут возникнуть ситуации, когда MySQL-функции или синтаксис нельзя преобразовать в подходящий DB2-формат. В таких ситуациях выясните, есть ли в PHP такая функция, и используйте эту функцию или расширение. Например, MySQL предоставляет SQL-функцию INET_ATON(), не имеющую эквивалента в DB2. Написание UDF-функции для INET_ATON() может оказаться занятием утомительным и подверженным ошибкам. К счастью, PHP имеет независящую от поставщика базы данных функцию ip2long() с аналогичной функциональностью.


Второй этап миграции исходного кода

Следующим действием после обновления и модификации SQL-выражений в PHP-коде для работы с данными по аналогии с MySQL является рефакторинг запросов для достижения нефункциональных целей улучшения целостности данных и повышения производительности. На этом шаге выполняются следующие действия:

Выбор соответствующего подхода к параллелизму

После преобразования в DB2-формат отдельных запросов, встроенных в MySQL-приложение, можно подумать об их улучшении для более полного использования возможностей DB2 в области параллелизма и поддержки целостности. Проанализируйте необходимость изменений для поддержки соответствующих уровней изоляции между несколькими параллельными соединениями с базой данных.

В DB2 имеется четыре уровня изоляции для управления параллелизмом. Уровни изоляции определяют, как транзакция скрывает текущие изменения данных, выполняемые другими пользователями. Поддерживаются следующие уровни изоляции:

Многократное чтение (repeatable read – RR)
Все строки блокируются до завершения транзакции.
Стабильность чтения (read stability – RS)
Строки, определяющие условие предиката, блокируются до завершения транзакции.
Стабильность на уровне указателя (cursor stability – CS)
Блокируются только те строки, в которых находится курсор. Этот уровень используется по умолчанию.
Чтение непринятого (uncommitted read – UR)
Строки не блокируются, пока данные не изменяются.

Решите, какой уровень изоляции подходит для вашего приложения с точки зрения производительности и целостности данных. При переходе с уровня UR на RR параллелизм уменьшается, а целостность данных растет. Уровень изоляции RR гарантирует максимальную целостность данных за счет снижения производительности. Наоборот, уровень UR гарантирует самую высокую производительность за счет некоторой противоречивости данных. На рисунке 1 показана взаимосвязь производительности и целостности данных.

Рисунок 1. Уровни изоляции в DB2
Уровни изоляции в DB2

Изоляцию можно определять на разных уровнях, от отдельных запросов до соединений и сеансов. Если большая рабочая нагрузка приходится на чтение данных, можно установить уровень изоляции в значение UR для соединения, чтобы не указывать его в каждом выражении. Если нагрузка распределяется на операции чтения и записи равномерно, можно сконцентрироваться на изменении отдельных запросов, а не уровня по умолчанию CS.

Также можно определить тип курсора, который следует использовать для оптимизации доступа к данным. Оба драйвера, ibm_db2 и PDO_IBM, поддерживают два типа курсоров: однонаправленный (forward-only) и двунаправленный (scrollable). По умолчанию используется однонаправленный курсор. Вообще говоря, значение по умолчанию подходит в большинстве ситуаций, когда итерирование по результатам запроса осуществляется последовательно. С точки зрения производительности однонаправленные курсоры лучше двунаправленных. Однако в некоторых случаях необходимо читать курсоры в обоих направлениях. В нашем примере сценария тип курсора устанавливается при помощи приведенных в листинге 15 команд для каждого запроса.

Листинг 15. Определение типа курсора DB2 из функции ibm_db2 и PDO-драйвера
-- Для ibm_db2
db2_exec($connection_resource, $sql, array('cursor' => DB2_SCROLLABLE));

-- Для PDO_IBM
$DB_PDO->prepare($sql, array(PDO::ATTR_CURSOR, PDO::CURSOR_SCROLL));

Более подробная информация приведена в разделе 4.2 "Использование PHP с базами данных DB2" документа Redbook "Разработка PHP-приложений для серверов данных IBM" (см. раздел Ресурсы).

Консолидация запросов для повышения качества данных и производительности

Сгруппируйте запросы в логические блоки. На этом этапе миграции кода, зная, что SQL-запросы выдают такие же результаты, а выражения изменяют данные так же, как это делалось в старом приложении, подумайте о перегруппировке запросов доступа к данным и обновлений. Цель – достичь уровня производительности MySQL и обеспечить уровень целостности данных DB2.

Уменьшение отношения количества соединений с базой данных к количеству выражений
Вообще говоря, соединения с базой данных в MySQL выполняются быстрее, чем в DB2. Поэтому уменьшение общего количества соединений в HTTP-запросе путем повторного использования соединения для нескольких запросов повышает производительность процессора, диска и сети. В нашем примере сценария мы консолидировали запросы, в том числе получение информации об учетной записи пользователя, таким образом, чтобы сразу выполнять более объемные соединения вместо использования нескольких последовательных поисковых запросов, как показано в листинге 16. В принципе это могло бы привести к предварительной выборке слишком большого объема данных, но в нашем примере производительность повысилась, объем выбираемых данных уменьшился, а разработчики лучше осознали, сколько данных действительно нужно извлекать для конкретной страницы, что тоже сэкономило ресурсы.
Листинг 16. Консолидация запросов
-- Два отдельных запроса, требующие двух заходов на сервер данных для страницы
SELECT FIN_PROJECT_MANAGER AS PM, PROJNAME FROM PROJECT WHERE ID = $id;
SELECT EMAIL, FIRSTNAME, LASTNAME FROM USER WHERE ID = $pm;

-- Один консолидированный запрос, извлекающий ту же информацию за один раз
SELECT U.EMAIL, U.FIRSTNAME, U.LASTNAME
FROM USER U, PROJECT P
WHERE U.ID = P.FIN_PROJECT_MANAGER 
AND PROJECT.ID = $id

Почему бы не мигрировать на Zend Framework?

Исходный код в нашем случае был разработан еще до появления большинства инфраструктур для PHP. Когда мы приступали к написанию PTT в 2002 году, повторно используемые компоненты из PEAR и библиотеки специального назначения, такие как уровни абстракции базы данных, только начали появляться. Полнофункциональные инфраструктуры, такие как CakePHP и Zend Framework появились на несколько лет позже. Внедрение Zend Framework – это желанная цель на будущее, но главной задачей миграции было получить стабильно работающий код для замены базы данных и заложить фундамент для этого.

Большой шаг вперед к более понятной MVC-архитектуре
В хорошо спроектированном трехуровневом Web-приложении, созданном с использованием архитектурного шаблона модель-представление-контроллер (model-view-controller – MVC), контроллер обрабатывает Web-запрос пользователя, а затем активизирует команду модели для подготовки ответа. Результат передается в представление (часто являющееся простым HTML-шаблоном) для отображения данных на странице. Исходное приложение не использовало шаблон MVC. Вместо этого приложение встраивало запросы непосредственно в шаблоны, фактически реализуя на одной странице три разные функции.

После внедрения рекомендованных MVC-методик группирования запросов (таких как получение всей информации об учетной записи пользователя и обо всех его проектах в одном запросе к модели) страница представления занимается только отображением информации, а не пошаговым извлечением дополнительных данных. Такой подход заменяет модель приложения, ориентированную на данные, моделью, ориентированной на бизнес-объекты, и соответственно помогает лучше организовать исходный код, отделяя логику доступа к данным от компоновки и разметки.

Оптимальное распределение рабочей нагрузки
В нашем сценарии, использующем один Web-сервер и один сервер базы данных, основную часть HTTP-трафика забирал на себя Web-сервер. Серверная логика приложения выполнялась на Web-сервере через PHP-модуль. Для повышения производительности HTTP-сервера за счет уменьшения потребления ресурсов ЦПУ и оперативной памяти, затрачиваемых на mod_php, часть бизнес-логики была перенесена на сервер данных. Во многих случаях это дало дополнительное преимущество в виде уменьшения сетевого трафика (уменьшался трафик между Web-сервером и сервером данных), и, следовательно, повышения производительности, поскольку обращение к данным и их обработка осуществлялись на одном уровне.
Улучшение целостности данных путем группирования запросов на сервере
Последним и самым важным преимуществом транзакционной целостности является группирование логики на сервере данных в атомарные транзакционные блоки с использованием хранимых процедур, триггеров и определяемых пользователем функций. Вы увидите, что создание заданий в таком приложении, как PTT, будет более надежным в случае, когда:
  • Все данные передаются в базу данных как единое целое.
  • Несколько выражений INSERT выполняются вместе как один блок.
  • Пользователю возвращается одно сообщение об успехе или неудаче.
Если бы мы использовали базу данных, не поддерживающую транзакции, в нашем сценарии могли бы неудачно завершиться одна или все операции изменения в базе данных, что сделало бы состояние системы непредсказуемым, требующим вмешательства пользователя или администратора для разрешения противоречивости данных, например, в результате частичного создания задания без указания владельца или другой важной взаимосвязи. В листинге 17 показан пример двух связанных обновлений, выполняющихся как атомарный блок.
Листинг 17. Группирование обновлений в хранимую процедуру
CREATE PROCEDURE BILLING_TYPE_UPDATE (IN p_date DATE)
BEGIN
    -- Обновление типа биллинга проекта
    FOR row AS 
       SELECT * 
       FROM proj_billingtype_snapshot
       WHERE end_date IS NULL
       AND start_date = p_date
       
	    DO
	       -- Выполнение двух обновлений в одной транзакции
	       t1: begin atomic   -- Транзакция начинается
	      
	       -- Первое обновление
	       UPDATE fin_attributes
	       SET proj_type = row.billing_type
	       WHERE project_id = row.proj_id;
	        
	       -- Второе обновление
	       UPDATE fin_attributes_archive
	       SET proj_type = row.billing_type
	       WHERE project_id = row.proj_id
	       AND year = YEAR(NOW());
	          
	       end t1;            -- Транзакция завершается
    END FOR;
END

Все версии DB2 поддерживают транзакции, но большинство механизмов хранения MySQL, в том числе применяемый по умолчанию MyISAM, не поддерживают их. Наше приложение по умолчанию использовало тип таблиц MyISAM, и разработчики пытались обеспечить целостность данных на уровне кода. Это было одним из стимулов для перехода на DB2, поскольку он позволил делегировать управление транзакциями базе данных, что DB2 делает очень хорошо. Кроме того, уменьшились размер и сложность всего исходного кода и его переносимых частей, которые должны работать совместно на любой PHP-странице приложения. Дополнительная информация о параллелизме в DB2 приведена в разделе 5.2.8 "Транзакции и уровень изоляции" документа Redbook "Разработка PHP-приложений для серверов данных IBM" (см. раздел Ресурсы).


Этап 3. Первоначальное тестирование вариантов использования заинтересованными лицами

Теперь у вас есть функциональная система, которую можно протестировать как единое целое, или по крайней мере как наборы связанных функций, составляющих отдельные компоненты. Например, создание нового задания, связанного с родительским проектом, является самодостаточным вариантом использования системы PTT. Отправка части содержимого (например, названия и описания продукта) в сервис преобразования – это еще один вариант использования, который можно протестировать отдельно. На этом шаге выполняются следующие действия:

Компиляция или создание приемо-сдаточных тестов

На данном шаге привлеките заинтересованных лиц к выполнению действий, которые они обычно выполняют на старой системе. Необходимо убедиться, что те же самые последовательности тестов работают на новой системе так, как ожидается.

В нашем сценарии применялся используемый годами и уже ставший стандартом формат приемо-сдаточных испытаний. Поэтому у нас был архив тестов для проверки новых возможностей и для предотвращения проблем регрессии в существующем коде. Набор тестов был расширен с адаптацией ядра критических функций к функциональности PTT. Такие тесты обычно инкапсулируют ряд связанных действий для достижения бизнес-целей и имеют сходство с диаграммой вариантов использования. Отличие от статической модели вариантов использования состоит в том, что тесты обычно хранятся в виде электронных таблиц вместе со снимками экрана и таблицами, содержащими обновляемые строки, в которые тестировщик может вводить информацию об успехе или неудаче отдельных действий или их последовательностей. В таблице 1 приведен пример формата приемо-сдаточного теста для проверки правильности создания задания.

Таблица 1. Пример приемо-сдаточного теста
ТестОжидаемый результатУспешно?
1. Создать новое задание1.1. Войти в систему.Отображается страница приветствия.Да
1.2. Открыть страницу нового задания.Загружается форма нового задания.Да
1.3. Заполнить и сохранить форму.Отображается сообщение об успехе и ссылка с уникальным идентификатором задания.Да
2. Подтвердить задание2.1. Войти в системуОтображается страница приветствия.Да
2.2. Найти список заданий.Загружается список заданий.Да
2.3. Нажать кнопку approve рядом с заданием.Отображается сообщение об успехе и отправляется письмо по электронной почте.Нет

Чрезвычайно важно, чтобы ваши тестировщики потратили достаточное количество времени на выполнение приемо-сдаточных тестов и зафиксировали все проблемы. Если тесты выполнять поверхностно, некоторые ошибки можно пропустить. По этой же причине важно сохранять информацию о том, кто проводил тестирование, в какое время и каковы были результаты, чтобы улучшить отслеживаемость.

Модульное тестирование и исправление проблем

На этом шаге систематически устраняются проблемы, выявленные тестировщиками при выполнении приемо-сдаточных тестов. После получения результатов тестирования отмеченные проблемы передаются конкретным разработчикам для проверки и исправления. Например, тест 2.3 в таблице 1 должен быть зарегистрирован как новый дефект.

По мере осуществления итеративной миграции системы разработчики должны сравнивать уже перенесенные в DB2 функции с оригинальной исходной системой MySQL, чтобы гарантировать правильность выполнения отдельных элементов работы. Возможно, имеет смысл автоматизировать приемо-сдаточные тесты при помощи таких инфраструктур модульного тестирования, как PHPUnit. Поскольку наш исходный код не слишком соответствовал MVC-модели, которая способствует тестированию программным способом, мы не использовали автоматизированные модульные тесты и интегрированные системы.

Создание базового образа

После завершения тестирования большого количества вариантов использования последним действием перед началом новой итерации тестирования является создание образа текущего состояния системы, предназначенного для использования в качестве резервной копии и базы для проверки функциональности и производительности. Опять же, по мере достижения стабильных промежуточных состояний в процессе итерационных изменений важно сохранять резервные копии. Это могут быть традиционные файловые или SQL-копии, а также образы всей операционной системы. Важно также хранить эти копии на случай возникновения ошибки в процессе разработки или для сравнения.


Этап 4. Устранение узких мест и проверка по критериям функциональности

После завершения набора приемо-сдаточных тестов и подписания результатов заинтересованными сторонами можно приступить к улучшению производительности системы. На данном этапе выполняются следующие действия:

Подтверждение базовых приемо-сдаточных тестов

При выполнении данного подготовительного шага важно напомнить, что необходимо хорошо представлять себе утвержденную функциональность системы, чтобы понимать, не будут ли какие-либо улучшения нефункциональных требований (например, улучшение производительности) отрицательно сказываться на утвержденных функциональных требованиях. Этот шаг следует выполнять после проверки функциональности по двум причинам. Во-первых, это гарантирует наличие базовой, заведомо работоспособной, утвержденной функциональности до выполнения каких-либо нефункциональных изменений. Во-вторых, это поможет избежать подводных камней преждевременной оптимизации. Возможно, вам известно, что определенный запрос (или подход) быстрее работает в одном случае, но это решение не следует слепо применять ко всему исходному коду, особенно если ничто не указывает на существование проблемы с производительностью.

В нашем примере мы вели историю приемо-сдаточных тестов для фиксации фактов и результатов тестирования и верификации возможных проблем регрессии в будущем.

Использование инструментальных средств для исправления проблем производительности в DB2

Риски преждевременной оптимизации

Вероятно, вы слышали сделанное в 1974 году замечание Дональда Кнута (Donald Knuth): "преждевременная оптимизация – корень всех зол". В качестве примера подводных камней, порождаемых такой оптимизацией, можно привести опыт одного из авторов данной статьи (мы не называем имен!). Узнав, что строки, заключенные в одинарные кавычки, выполняются лучше, чем строки, заключенные в двойные кавычки (благодаря тому что при использовании одинарных кавычек не замещаются интерполированные переменные), он решил, что было бы неплохо заменить все двойные кавычки одинарными. У него не было оснований считать, что приложение испытывает проблемы с производительностью, но он выполнил то, что задумал, путем довольно кропотливого поиска и замены. К сожалению, он пропустил одну или две интерполированные строки и внес трудноуловимую ошибку, которая вызвала проблемы с целостностью данных. Однако мы простили его.

Тестирование на данном этапе следует сосредоточить на том, что автоматически может исправить сама DB2, поскольку переход на DB2 – это самое большое проведенное вами изменение. При модификации кода, выполнении модульных и приемо-сдаточных тестов следует определить узкие места и выполнить необходимые изменения. Необходимо следовать главному правилу – изменять только то, что вызывает проблемы при выполнении модульных и приемо-сдаточных тестов, а не предполагаемые источники потенциальных проблем с производительностью. После этого можно задокументировать выполненные изменения и сохранить их для использования в будущем при возникновении проблем.

Здесь существует тонкий баланс между преждевременной оптимизацией и массированным применением исправлений на основе передовых методик. Процесс должен быть итеративным на протяжении всего периода эксплуатации приложения. Обратите внимание на замечание о рисках предварительной оптимизации на врезке.

Одной из методик, которая может оказаться полезной, является реализация функции для примера приложения PTT, которая отслеживает сценарии, выполняющиеся более 60 секунд, и отправляет отчет об ошибках. Пример такой функции рассматривается в четвертой части данной серии.

На основе информации этого отчета можно определить, что является причиной проблемы: медленное выполнения PHP-функции или медленный запрос. Если проблема в PHP, ее можно локализовать при помощи отладчика, например, из Zend Studio или Eclipse PDT. Если проблема в запросе, ее можно локализовать и исправить при помощи IBM Data Studio. На рисунке 2 показан пример схемы плана доступа для запроса.

Рисунок 2. Настройка запроса в IBM Data Studio
Настройка запроса в IBM Data Studio

Поиск и устранение узких мест в операционной системе

После устранения проблем с производительностью приложения, вызванных DB2 или PHP, следует выполнить итеративный поиск дополнительных узких мест производительности, используя метод проб и ошибок, описанный Джоном Коггешеллом (John Coggeshall) в статье "Корпоративные PHP-шаблоны Zend" (см. раздел Ресурсы). Если говорить коротко, поиск можно начать с трех общих источников узких мест, чтобы понять, можно ли решить какие-либо проблемы производительности путем простого обновления аппаратного обеспечения или путем настройки ресурсов, выделенных виртуальной машине:

  • Процессор
  • Оперативная память
  • Диск

Хотя многие инструментальные средства, используемые в Zend для определения узких мест производительности, применяются в ОС Linux, многие методики можно реализовать и средствами Windows при разработке или после развертывания обновленного приложения на тестовом сервере, промежуточном сервере и затем после сдачи в эксплуатацию.


Этап 5. Оценка итогов миграции кода

Выполнив этапы 1-4, которые сами могут потребовать нескольких итераций, мы имеем функциональную систему базы данных на рабочей станции Windows и записи об изменениях и возникших проблемах. Если использовались виртуальные машины, мы также получаем сохраненные образы системы Windows как для архивирования текущего рабочего состояния, так и для использования в качестве основы для сравнения последующих изменений производительности. Другим вариантом, естественно, является использование виртуального образа в облаке IBM или Amazon Cloud и работа с ним аналогичным способом. Можно поэкспериментировать с разными способами модификации кода для определения наиболее подходящего для вашей среды.

Если вы удовлетворены работой системы на рабочей станции Windows на этапах 1-4, можно зафиксировать модифицированный код как версию для выпуска в системе управления версиями и подготовить инфраструктуру для предшествующих развертыванию завершающих этапов, описанных в четвертой части данной серии статей (EN).


Заключение

Данная статья предоставляет подробную информации о том, что обычно требуется для переноса PHP-приложения с MySQL на DB2 и о том, какими ресурсами при этом можно воспользоваться. В статье также приведен пример успешной миграции.

В третьей части серии статей вы:

  • познакомились с исходным PHP-кодом;
  • узнали, как модифицировать приложение для работы с DB2;
  • узнали, как протестировать и настроить код после его преобразования.

В четвертой части данной серии статей вы узнаете, как развернуть мигрированное приложение и обеспечить постоянную поддержку.

Благодарности

Авторы благодарят Леонса Петразикиса (Leons Petrazickis) и Эмбриша Бхаргава (Ambrish Bhargava) за комментарии к статье.

Ресурсы

Научиться

Получить продукты и технологии

  • Получите IBM DB2 e-kit for Database Professionals для изучения возможностей DB2, использования вашего опыта разработки приложений и администрирования баз данных, подключения к сообществу DB2 и подготовки к экзаменам по сертификации.
  • Свяжитесь с группой Software Migration Project Office DB2, чтобы получить бесплатную оценку возможности миграции.
  • Создавайте и проверяйте ваши PHP/DB2-приложения в IBM Cloud при помощи сервиса IBM Smart Business Development and Test on the IBM Cloud.
  • Попробуйте поработать с DB2 на Amazon EC2.
  • Zend Server – – сервер Web-приложений корпоративного уровня для выполнения и поддержки PHP-приложений, предъявляющих высокие требования к надежности, производительности и безопасности, на Linux, Windows или IBM i.
  • Zend Server включает в себя драйверы для DB2, но для собственных конфигураций PHP можно использовать исходный код расширения драйвера в виде PECL или бинарных файлов для Windows на сайте SourceForge.
  • Дополнительная информация по обучению и сертификации по DB2. Пройдите учебный курс по управлению информационными ресурсами.
  • Загрузите и установите бесплатный сервер данных DB2 Express-C.
  • Используйте Rational Software Architect или InfoSphere Data Architect для выполнения логического и физического моделирования данных.
  • Используйте Optim Development Studio для разработки и оптимизации приложений, работающих с DB2.
  • Используйте бесплатную программу VMware vCenter Converter для преобразования физических машин в виртуальные образы.

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Information Management, Open source
ArticleID=820398
ArticleTitle=Перенос PHP-приложений с MySQL на DB2: Часть 3. Преобразование PHP-кода
publish-date=06082012