Использование нескольких баз данных в CodeIgniter

Владимир | | CodeIgniter, PHP, Web разработка.

codeigniter multiple db

В этой статье я хочу рассказать о возможностях, которые предоставляет PHP фреймворк CodeIgniter для одновременной работы с несколькими базами данных. Кроме того, я провел небольшое исследование производительности.

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

Т.е. вызвать два раза функцию mysql_connect (если, конечно, используете MySQL).

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

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

Я расскажу о подключении и использовании нескольких баз данных в CodeIgniter. Но, естественно, это не единственный фреймворк, который имеет встроенные библиотеки для работы с несколькими БД. Например, недавно я читал статью «Работа с несколькими базами данных при помощи ORM в Zend Framework».

В качестве примера рассмотрим подключение к двум БД.

1) Указываем параметры подключения в конфигурационном файле.

Открываем файл application/config/database.php и ищем блок с настройками подключения к базе.

$db['default']['hostname'] = "localhost";
$db['default']['username'] = "db_user";
$db['default']['password'] = "db_pass";
$db['default']['database'] = "db_name";
$db['default']['dbdriver'] = "mysql";
$db['default']['dbprefix'] = "";
$db['default']['pconnect'] = FALSE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = "";
$db['default']['char_set'] = "utf8";
$db['default']['dbcollat'] = "utf8_general_ci";

Как видите, все параметры подключения находятся в двумерном массиве. В первом индексе указывается название группы параметров данного подключения (в данном случае default).

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

Например,

$db['db2']['hostname'] = "localhost";
$db['db2']['username'] = "db2_user_name";
$db['db2']['password'] = "db2_pass";
$db['db2']['database'] = "db2_name";
$db['db2']['dbdriver'] = "mysql";
$db['db2']['dbprefix'] = "";
$db['db2']['pconnect'] = FALSE;
$db['db2']['db_debug'] = TRUE;
$db['db2']['cache_on'] = FALSE;
$db['db2']['cachedir'] = "";
$db['db2']['char_set'] = "utf8";
$db['db2']['dbcollat'] = "utf8_general_ci";

2) Подключаемся к нужной базе.

Просто два раза используем стандартный способ подключения к БД в CodeIgniter.

$DB = $this->load->database('default', TRUE, TRUE);
$DB2 = $this->load->database('db2', TRUE, TRUE);

При этом в первом параметре указываем название группы параметров нужного подключения. В данном случае это 'default' и 'db2'.

Второй параметр в данном случае обязательно должен быть равен TRUE. Он указывает должен ли метод database вернуть ID соединения. По-умолчанию этот параметр равен FALSE, т.к. в большинстве случаев работать нужно только с одной БД. Но если баз две или больше, то с помощью этих ID можно указать какой базе отправляется запрос.

Третий параметр не обязательный. С его помощью мы указываем активировать или нет класс Active Record.

3) Отправляем запросы.

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

Т.е. если в случае одной базы запрос отправляется через объект $this.

$this->db->query('…');

То при работе с двумя базами отправка запроса будет выглядеть так:

$DB->query('select * from table_name');
$DB2->query('select * from db2_table_name ');

Как видите, код даже немного сокращается.

Потребление ресурсов.

Думаю, не сложно догадаться, что подключение ко второй базе займет какое-то время. Поэтому я решил провести небольшой тест.

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

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

Подключение к одной БД.

Вызов php::mysql_connect происходит в методе CI_DB_mysql_driver->db_connect и занимает 4.32 мс.

При этом общее время работы скрипта 131 мс.

Подключение к двум БД.

php::mysql_connect вызывается два раза (также из CI_DB_mysql_driver->db_connect) и занимает 5.99 мс.

Общее время — 132 мс.

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

Кстати, даже самый простой запрос (к одной маленькой таблице без условий) занимает около 30 мс.

Пожалуй, единственный недостаток в том, что при использовании двух БД не работает встроенный в CodeIgniter профайлинг.

Правда, недавно видел инструкцию по исправлению этого недостатка, но сам не пробовал.

Как видите, в использовании нескольких БД нет ничего сложного. Если возникли вопросы, задавайте, попробую ответить 😉

  • Pingback: Linkdump #5 | CTAPbIu_MABP's BLOG()

  • Sam

    Профайлинг исправили в 1.7:

    Added controller class/method info to Profiler class and support for multiple database connections.

    • Точно, это моя ошибка.
      Правда по-моему все-равно что-то в нем недоделано 🙂 … или я не до конца разобрался.
      Первый эксперимент.
      Коннекчусь к 2-ум базам (в конструкторе контроллера) и выполняю по запросу к каждой из них (в одном из методов).
      Результат — в разделе QUERIES «Database driver is not currently loaded».
      Подключаю в autoload.php
      $autoload['libraries'] = array('database');
      Результат — «No queries were run»
      Только после отправки запроса обычным методом
      $this->db->query…
      Отправленный запрос появился в результатах.

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

  • Sam

    Профайлинг исправили в 1.7:

    Added controller class/method info to Profiler class and support for multiple database connections.

    • Точно, это моя ошибка.
      Правда по-моему все-равно что-то в нем недоделано 🙂 … или я не до конца разобрался.
      Первый эксперимент.
      Коннекчусь к 2-ум базам (в конструкторе контроллера) и выполняю по запросу к каждой из них (в одном из методов).
      Результат — в разделе QUERIES «Database driver is not currently loaded».
      Подключаю в autoload.php
      $autoload['libraries'] = array('database');
      Результат — «No queries were run»
      Только после отправки запроса обычным методом
      $this->db->query…
      Отправленный запрос появился в результатах.

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

  • Алексей

    только вот со временем запроса самого простого запроса вы круто преувеличили, вот простое исследование:
    таблица 30 мб, запрос «SELECT * FROM `data` LIMIT 0 , 30» занимает всего 0.0008 секунд.

    • У вас запрос на выборку (0.8мc), а у меня — на подключение к базе (4.32мс).
      По-моему вполне реальные цифры.

  • Алексей

    только вот со временем запроса самого простого запроса вы круто преувеличили, вот простое исследование:
    таблица 30 мб, запрос «SELECT * FROM `data` LIMIT 0 , 30» занимает всего 0.0008 секунд.

    • У вас запрос на выборку (0.8мc), а у меня — на подключение к базе (4.32мс).
      По-моему вполне реальные цифры.

  • Спасибо вам большое!
    Мы как раз решили использовать несколько баз данных для своего проекта. И очень мучил вопрос с производительностью.
    Благодарю за вашу статью!

  • Спасибо вам большое!
    Мы как раз решили использовать несколько баз данных для своего проекта. И очень мучил вопрос с производительностью.
    Благодарю за вашу статью!

  • Максим

    По третьему пункту с вами не согласен.
    У меня в приложении получилось что в autoload стояло:
    $autoload['libraries'] = array('database');
    и по всему приложению используется
    $this->db->query
    когда же была подключено второе соединение
    $db2 = $this->load->database('db2', TRUE, TRUE);
    то для запросов из него стал использовать $query = $dbf->query, но для первого соединения остается $this->db->query

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

    • Александр Авдюков

      Спасибо за это существенное замечание, а то у меня не было запланировано использовать изначально. И мне охота было везде переписывать по новому))

  • Максим

    По третьему пункту с вами не согласен.
    У меня в приложении получилось что в autoload стояло:
    $autoload['libraries'] = array('database');
    и по всему приложению используется
    $this->db->query
    когда же была подключено второе соединение
    $db2 = $this->load->database('db2', TRUE, TRUE);
    то для запросов из него стал использовать $query = $dbf->query, но для первого соединения остается $this->db->query

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

  • Запускаю контроллер cron_site

    Обращаюсь сначала к методу модели который обращается к сайту.
    В самом начале метода модели пишу:
    $db_site = $this->load->database('site', TRUE, TRUE);

    После чего из контроллера cron_site обращаюсь к другому методу модели которая в свою очередь работает с дефолтовой базой вот так $this->db

    В итоге в профайлере вижу запросы только дефольтовой базы данных!
    Запросы к сайту не видны…

    В config/autoload.php прописано
    $autoload['libraries'] = array('database');

    Подскажите пожалуйста, в чем подвох?

    У меня CI 1.7.2

    • Mail

      попробуйте в конфиге database.php pconnect поставить в FALSE