Работа с соединениями

Функции подключения

Расширение OCI8 предоставляет три различных функции для подключения к серверу Oracle. Стандартная функция соединения - это oci_connect(). Она создает соединение к базе данных Oracle и возвращает ресурс, который используется при последующих обращениях к БД.

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

Если приложение соединяется к серверу Oracle, используя особый набор данных для каждого веб-пользователя, то постоянный кэш соединений, используемый функцией oci_pconnect() будет менее полезным, т.к. количество одновременных пользователей вырастает до того уровня, где он может начать оказывать негативное влияние на общую производительность сервера Oracle из-за поддержания слишком большого количества простаивающих соединений. Если приложение настроено таким образом, то рекомендуется либо настроить его с помощью параметров конфигурации oci8.max_persistent и oci8.persistent_timeout (это даст возможность управления размером кэша постоянных соединений и их время жизни), либо использовать Oracle 11g Database Resident Connection Pooling, либо использовать функцию oci_connect() вместо нее.

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

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

Кеш функции oci_pconnect() очищается и закрываются все соединения к БД, когда завершается процесс PHP. Поэтому эффективное использование постоянных соединений требует, чтобы PHP был модулем Apache или использовался с FCGI или подобным. Постоянные соединения не будут иметь никаких преимуществ перед oci_connect(), когда PHP используется с CGI или через командную строку.

Функция oci_new_connect() всегда создает новое соединение с сервером Oracle, невзирая на то, что другие соединения могут уже существовать. Высоконагруженным веб-приложениям следует избегать использования oci_new_connect(), особенно в самых загруженных частях приложения.

Создание пула соединений DRCP

PHP 5.3 (PECL OCI8 1.3) поддерживает постоянный пул соединений Oracle 11g (DRCP). DRCP позволяет более эффективно изпользовать память СУБД и предоставляет высокую масштабируемость. Изменять код приложения для использования DRCP либо нет необходимости, либо требуются минимальные изменения.

DRCP подходит для приложений, которые подключаются используя несколько схем БД и сохраняют соединения к БД открытыми короткий промежуток времени. Другим приложениям следует использовать доступные по умолчанию Dedicated серверные процессы или использовать Shared сервера.

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

Чтобы функционал DRCP был доступен в OCI8, клиентские библиотеки Oracle, используемые в PHP, и версия сервера баз данных должны быть 11g.

Документация по DRCP находится в нескольких руководствах Oracle. К примеру, см. » Конфигурирование пула постоянных соединений базы данных в документации Oracle для информации по использованию. Документ » техническое описание DRCP содержит дополнительную информацию по DRCP.

Для использования DRCP, скомпилируйте PHP с расширением OCI8 1.3 и библиотеками Oracle 11g и затем выполните следующие действия:

  • Как привилегированный администратор БД воспользуйтесь программой наподобие SQL*Plus, чтобы запустить пул соединений в СУБД:

        SQL> execute dbms_connection_pool.start_pool;
    

  • Дополнительно можно использовать dbms_connection_pool.alter_param(), чтобы конфигурировать параметры DRPC. Текущие настройки пула могут быть получени из представления DBA_CPOOL_INFO.

  • Обновите используемую строку соединения. К примеру, для приложений PHP, которые сейчас соединяются, используя Network Connect Name MYDB:

        $c = oci_pconnect("myuser", "mypassword", "MYDB");
    

    измените файл tnsnames.ora и добавьте оператор (SERVER=POOLED), например:

        MYDB = (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp) (HOST=myhost.dom.com)
               (PORT=1521))(CONNECT_DATA=(SERVICE_NAME=sales)
               (SERVER=POOLED)))
    

    В качестве альтернативы можно изменить синтаксис упрощенного соединения в PHP и добавить туда :POOLED после имени сервиса:

        $c = oci_pconnect("myuser", "mypassword", "myhost.dom.com:1521/sales:POOLED");
    

  • Отредактируйте php.ini и выберите имя класса соединения. Это имя устанавливает логическое разделение пула соединений и может использоваться, чтобы изолировать пул для отдельных приложений. Любое PHP-приложение с одинаковым именем пользователя и классом для соединения будет иметь возможность совместно использовать соединения в пуле, получая бОльшую масштабируемость.

        oci8.connection_class = "MY_APPLICATION_NAME"
    

  • Запустите приложение, соединяющееся с базой 11g.

Замечание:

Приложения, использующие Oracle 10g, которые требуют производительности от постоянных соединений, могут уменьшить количество памяти сервера БД, которое используется Shared-серверами Oracle (ранее известные как многопоточные сервера). Обратитесь к документации Oracle для более подробной информации.

Рекомендации по DRCP и известные ограничения

При изменении пароля через DRCP-соединение будет выдаваться ошибка ORA-56609: Usage not supported with DRCP. Это документированное ограничение of Oracle Database 11g.

C расширением OCI8 версии 1.3 постоянные соединения теперь могут быть закрыты пользователем. Это позволяет получить больший контроль над использованием ресурсов соединений. Постоянные соединения теперь будут также закрываться автоматически, когда отсутствует указывающая на них переменная PHP, например, в таких случаях, как в конце области видимости пользовательской функции PHP. Это откатит любую незавершенную транзакцию. Эти изменения в постоянных соединениях делают их поведение похожим на поведение непостоянных соединений, упрощая интерфейс и позволяя приложениям быть более логичными и предсказуемыми. Для сохранения предыдущего поведения используйте директиву oci8.old_oci_close_semantics, принимающую значение On .

Если СУБД Oracle версии 11.1.0.6, то для использования DRCP должен быть применен патч для СУБД Oracle для устранения ошибки 6474441. Без этого патча могут происходить ошибки, такие как ORA-01000: maximum open cursors exceeded, ORA-01001 invalid cursor или ORA-01002 fetch out of sequence. Эти ошибки исправлены в Oracle версии 11.1.0.7 и более поздних.

Если патч для СУБД Oracle 11.1.0.6 не может быть применен, тогда вместо этого можно воспользоваться тремя методами:

  • Соединение используя Oracle Dedicated или Shared сервера вместо DRCP.
  • Установить директиву PHP oci8.statement_cache_size в 0.
  • Установить событие в файле параметров инициализации базы: event="56699 trace name context forever, level 128".

Патч 6474441 для БД Oracle версий 11.1.0.7 и 11.1.0.6 позволяет приложениям на PHP с DRCP-соединением использовать триггер базы LOGON для установки параметров сессии в момент ее создания. Примерами таких параметров являются язык NLS и формат даты.

Если патч к БД Oracle 11.1.0.6 не может быть установлен, то можно использовать несколько методов вместо использования триггеров LOGON:

  • После авторизации, явно установите свойства сессии используя код приложения PHP.
  • Соединитесь, используя Oracle Dedicated или Shared сервера вместо DRCP.

Автоматическое повторное установление постоянного соединения PHP после порождения нового процесса Apache или FGCI означает, что использование триггеров LOGON в PHP рекомендуется только для установки атрибутов сессии, а не для пользовательских запросов на соединение для каждого приложения. Это даже более проявляется с DRCP за счет автоматического изменения размера буфера соединений и со способом триггеров LOGON конфликтующим с DRCP аутентификацией.

Поддержка быстрого оповещение приложения (FAN)

Поддержка FAN дает быструю обработку ситуации отказа соединения и высокую доступность. Это посволяет скриптам PHP OCI8 быть уведомленными когда компьютер или экземпляр базы данных становится недоступным. Без FAN, OCI8 может зависнуть до тех пор, пока не пройдет таймаут TCP и не возвратится ошибка, что может занимать несколько минут. Включение FAN в OCI8 позволяет приложениям определять ошибки и подсоединяться заново к доступному экземпляру базы данных без уведомления веб-пользователя о перебое в работе.

Поддержка FAN доступна, когда клиентские библиотеки Oracle, с которыми был собран PHP и СУБД Oracle, вместе имеют версию 10gR2 или 11g.

FAN приносит пользу пользователям кластерной технологии Oracle (RAC), потому что соединения к оставшимся работоспособными экземплярам базы может быть осуществлено незамедлительно. Пользователи Oracle Data Guard с брокером будут видеть сгенерированные события FAN, когда резервная база данных становится доступной. Автономные базы данных будут посылать FAN-события, когда база будет перезагружена.

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

Когда директива oci8.events принимает значение On, рекомендуется установить oci8.ping_interval в -1 для выключения пинга, так как включение FAN-событий, предоставляющих упреждающее управление неиспользуемыми соединениями, сделает его невозможным из-за нарушения обслуживания.

Для включения поддержки FAN в PHP необходимо собрать PHP с библиотеками Oracle 10gR2 или 11g и затем следовать следующим инструкциям:

  • Как привилегированный администратор баз данных, используйте программу, подобную SQL*Plus, для включения сервиса БД по отправке FAN-событий. Например:

        SQL> execute dbms_service.modify_service(
                       SERVICE_NAME        => 'sales',
                       AQ_HA_NOTIFICATIONS => TRUE);
    

  • Отредактируйте php.ini и добавьте

        oci8.events = On
    

  • Если приложение не обрабатывает ошибочные состояния OCI8, модифицируйте его, чтобы определить ошибки и принять соответствующие действия. Это может включать повторное соединение и повторное выполнение выражений.
  • Запустите приложение, соединяющееся к базе Oracle 10gR2 или 11g.


Участник рейтинга Тэглайн 2010