Работа с базами данных с использованием класса ADODB
Maxim Matyukhin
Содержание
- Пару слов об ADODB
- Установка
- Примеры использования
- Особенности
- ADODB & PEAR
- Заключение
1. Пару слов об ADODB
Для начала, скажу что статья рассчитана на программистов, имеющих опыт работы с
СУБД, а не на начинающих пхпешников.
Я предполагаю, что вы знакомы с PHP, ОПП, SQL и имеете опыт разработки
web-приложений.
ADODB - это класс доступа к базам данных, написанный на PHP.
Он позволяет с легкостью переносить скрипты под использование различных СУБД.
Например если бы вы не использовали класс доступа к БД и вам нужно было бы
скрипты, работающие с mysql, перевести под работу с PostgreSQL, то вам пришлось бы
- заменить весь код работы с mysql на postgresql
- переписать SQL-запросы (так как есть отличия)
Если бы вы использовали класс доступа к БД, то вам скорее всего не
пришлось бы менять php-код (только в одном месте указали бы, что используете
postgresql) и изменить SQL-запросы (хотя иногда и это не понадобилось бы).
Я намеренно в этом описании использовал фразу "класс доступа к БД",
поскольку ADODB - не единственный подобный класс. Наиболее известные конкуренты:
Многие пишут такие классы сами, но я не сторонник изобретения велосипедов.
Противники таких массивных классов, как ADODB или Pear::DB утверждают,
что их использование плохо сказывается на производительности. Да,
производительность падает и это вполне логично. НО:
- Скорость не часто является самым важным фактором
(Мало кто из вас пишет сайты с очень большой нагрузкой, на которых
бы это снижение производительности стало критичным)
- Использование таких классов повышает производительность программиста
- При использовании софта, типа phpAccelerator падение производительности
будет не таким заметным (и я не поверю, что популярные сайты не имеют
возможности использовать такой софт)
- Разработчики ADODB написали php-extension, который
ускоряет работу класса (но работать можно и без него)
От себя могу добавить, что многие из написанных мною сайтов
используют ADODB и проблем с производительностью не имеют.
2. Установка
Здесь все просто.
Скачайте с http://php.weblogs.com/adodb архив и распакуйте его (например в папку ./adodb)
Все, класс готов к использованию.
Можете еще скачать и php-extension, но я его использовать не пробовал
Чтобы использовать класс, вам необходимо включить (include) файл ./adodb/adodb.inc.php
3. Примеры использования
Пример 1
<?
// подключаем класс
include_once("adodb/adodb.inc.php");
// указываем тип БД
$conn = &ADONewConnection('mysql');
// соединяемся с БД
$conn->Connect('localhost', 'user', 'password', 'db_name');
// режим отладки - включен (true)
$conn->debug = true;
$conn->setFetchMode(ADODB_FETCH_ASSOC);
?>
Данный пример демонстрирует подключение к БД. В строке
<? $conn = &ADONewConnection('mysql'); ?>
создается объект соединения с базой данных. Именно через поля и методы данного
объекта и будет в дальнейшем вестись работа с базой данных.
Что касается режима отладки, то по умолчанию он выключен. При включенном
режиме отладки на экран броузера будут выводиться SQL-запросы и тексты ошибок
(если такие были). Очень упрощает процесс написания и отладки скриптов.
Метод $conn->setFetchMode() - указывает, каким образом данные о
записях будут записаны в массив - будет ли это
ассоциативный массив, или простой нумерованный или и тот и другой.
Ей нужно установить одно из значений (0, 1, 2, 3). Для пояснений приведу код
из исходников adodb:
<?
define('ADODB_FETCH_DEFAULT',0);
define('ADODB_FETCH_NUM',1);
define('ADODB_FETCH_ASSOC',2);
define('ADODB_FETCH_BOTH',3);
?>
Судя по исходникам ADODB_FETCH_DEFAULT == ADODB_FETCH_BOTH
Теперь сделаем запрос к БД:
<?
// делаем запрос к БД
$res = $conn->Execute("SELECT id, title, description FROM tab");
// если по запросу найдены записи в таблице
if ($res && $res->RecordCount() > 0) {
// выводим эти записи в цикле
while (!$res->EOF) {
echo "ID = ".$res->fields['id']."\n";
echo "title = ".$res->fields['title']."\n";
echo "description".$res->fields['description'];
// переходим к следующей записи
$res->MoveNext();
}
}
?>
Вот простейший пример запроса к БД.
Метод $conn->Execute() выполняет запрос к базе данных и возвращает
множество записей (recordset).
Множество записей (recordset) - в ADODB является отдельным объектом,
который имеет свои поля и методы для работы с полученными записями. Некоторые
из них использованы в данном примере.
- $res->EOF - равен true если обработаны все записи множества
- $res->fields - хранит ассоциативный массив значений текущей записи
- $res->RecordCount() - возвращает количество строк, полученных входе
выполнения запроса
- $res->MoveNext() - переходит к следующей записи (в массив
$res->fields будет занесена следующая запись множества)
Метод $conn->Execute() - может быть использован для любых запросов:
<?
// делаем вставку строки
$conn->Execute("INSERT INTO tab(name, value) VALUES ('name', 'ha ha ha')");
// получаем идентификатор вставки
// аналог mysql_insert_id();
$id = $conn->Insert_ID();
$conn->Execute("DELETE FROM tab WHERE id = ".$id);
?>
Опишу еще некоторые полезные методы класса AdoConnection:
- $conn->getRow($sql) - возвратит массив со значениями первой записи из всего
множестве найденных записей.
- $conn->getAll($sql) - возвратит 2-мерный массив со всеми найденными
записями
4 Особенности
Думаю этот раздел будет наиболее интересен программистам.
- 4.1 Постраничный вывод и ограничение SELECT-запросов
- Вообще-то не все базы данных умеют делать запросы типа:
SELECT * FROM tab LIMIT 0, 10
а все те, которые умеют, делают это по разному:
- MySQL:
- SELECT * FROM tab LIMIT 0, 10
- PostgreSQL:
- SELECT * FROM tab OFFSET 0, LIMIT 10
- FireBird:
- SELECT FIRST 10 SKIP 0 * FROM tab
Класс adodb сам может делать ограниченные выборки, составляя правильные
SQL-запросы под указанную БД, поддерживающую лимитированные SELECT-запросы
<? $res = $conn->SelectLimit("SELECT * FROM tab", 10, 0); ?>
Метод $conn->SelectLimit() сам построит правильный SQL-запрос
На основе этого метода в ADODB работают функции для постраничной выборки:
<?
// определяем текущую страницу
$start = max(1, intval($_GET['start']));
// количество записей на странице
$rows_per_page = 10;
$res = $conn->PageExecute("SELECT * FROM tab", $rows_per_page, $start);
// получаем найденное количество записей
$records_amount = $res->MaxRecordCount();
?>
Метод $conn->PageExecute() кроме простого LIMIT-запроса делает автоматически
еще и запрос типа:
SELECT COUNT(*) FROM tab
Таким образом он сам узнает, сколько всего по данному запросу найдено строк.
Это количество можно узнать с помощью метода:
$res->MaxRecordCount();
Также для управления постраничным выводом есть следующие методы:
- $res->AbsolutePage() - возвращает текущую страницу
- $res->AtFirstPage() - возвращает true если текущая страница - первая
- $res->AtLastPage() - возвращает true если текущая страница - последняя
- $res->LastPageNo() - возвращает номер последней страницы
- 4.2 Генерирование INSERT/UPDATE запросов
- Для начала пример:
<?
// пример генерирования INSERT-запроса
// массив, который нужно вставить в таблицу
$frm = array("field1"=>"value1", "field2"=>"value2");
// делаем пустой запрос
$res = $conn->Execute("SELECT * FROM tab WHERE id = -1");
// формируем SQL-запрос
$sql = $conn->GetInsertSQL($res, $frm);
// выполняем запрос
$conn->Execute($sql)
// пример генерирования UPDATE-запроса
// получаем данные о строке, которую нужно обновить
$res = $conn->Execute("SELECT * FROM tab WHERE id = 17");
$sql = $conn->GetUpdateSQL($res, $frm);
// выполняем запрос
$conn->Execute($sql)
?>
Так вот идея в том, чтобы все данные, которые нужно вставить записать в
ассоциативный массив. Сделать запрос к БД чтобы получить имена полей
таблицы и сконструировать SQL-запрос по этим данным.
Уверен, что будет много противников этого метода
(мол лишний SQL-запрос к БД делать), но мне эти функции кажутся очень удобными.
- 4.3 Работа с транзакциями
- Ну это вообще сказка :). Вот пример из мануала:
<?
$conn->StartTrans();
$conn->Execute("update table1 set val=$val1 where id=$id");
$conn->Execute("update table2 set val=$val2 where id=$id");
$conn->CompleteTrans();
?>
Метод $conn->CompleteTrans(); сам проверит, были ли ошибки и если так
- сделает откат.
ADODB имеет еще и другие функции для работы с транзакциями, но они устарели
и разработчики ADODB рекомендуют использовать этот вариант.
- 4.4 Последовательности
-
Часто при работе с таблицами каждой записи нужно присвоить уникальный
идентификатор, который потом используется в качестве первичного ключа.
Но не все СУБД поддерживают такую возможность. ADODB эмулирует эту
возможность почти для всех СУБД. На практике это выглядит примерно так:
<?
$uid = $conn->GenID('site_users');
$conn->Execute("INSERT INTO site_users(uid, login, password) VALUES(".$uid.", '$login', '$password')");
?>
Метод $conn->GenID() создает последовательность site_users
(если она до этого не была создана) и возвращает значение на единицу больше
чем текущее значение последовательности.
- 4.5 Кеширование запросов
- ADODB поддерживает серверное кеширование запросов. Суть в том, что при
первом выполнении запроса его результаты заносятся в кеш-файл. При
последующем таком же запросе (если кеш-файл не устарел) данные будут браться
из файла.
Честно говоря, мне не нравится метод, которым они производят кеширование
(по-моему они слишком уж универсальным сделали его) и предпочитаю делать
кеширование своими руками.
Если вас все-таки интересует кеширование, то работает оно так:
<?
$ADODB_CACHE_DIR = '/tmp/ADODB_cache';
$rs = $conn->CacheExecute('SELECT * FROM tab');
?>
По умолчанию время жизни кеш-файлов - 1 час. Это время можно изменить 2-мя путями:
<?
$conn->cacheSecs = 24*3600 // 24 часа
$rs = $conn->CacheExecute('SELECT * FROM tab');
// или так:
// время жизни кеша может задаваться первым параметром
// метода CacheExecute
$rs = $conn->CacheExecute