ГлавнаяBTL инфоПрограммированиеDatabase
Статьи

ADODB – русская документация
 

Объектно-ориентированное программирование. Абстрактные классы БД
 

Абстрактный доступ к БД с помощью ADODB
 

Вступление в PHP и MySQL
 

Оптимизация запросов в MySQL
 

Работа с MySQL. Деревья
 

Работа с MySQL: Подробнее
 

Первые шаги: работа с базами данных
 

Объектно-ориентированные базы данных - основные концепции,
 

ВВЕДЕНИЕ В РЕЛЯЦИОННУЮ БАЗУ ДАННЫХ
 


1 2 
В начало Предыдущая Следующая В конец
 

 include(\'adodb.inc.php\'); 
$db = &ADONewConnection("ado_mssql");
print "<h1>Соединение DSN-less $db->databaseType...</h1>";
        
$myDSN="PROVIDER=MSDASQL;DRIVER={SQL Server};"
        . "SERVER=flipper;DATABASE=ai;UID=sa;PWD=;"  ;
$db->Connect($myDSN);

$rs = $db->Execute("select * from table");
$arr = $rs->GetArray();
print_r($arr); 
1 2 3 4 
В начало Предыдущая Следующая В конец
 

Абстрактный доступ к БД с помощью ADODB

 

1. Пару слов об ADODB

Для начала, скажу что статья рассчитана на программистов, имеющих опыт работы с СУБД, а не на начинающих пхпешников. Я предполагаю, что вы знакомы с PHP, ОПП, SQL и имеете опыт разработки web-приложений.
ADODB — это абстрактный класс доступа к базам данных, написанный на PHP.
Для тех, кто в танке поясню на примере.
Предположим вы написали скрипт под mysql. И тут заказчик говорит Вам, что хостинг меняется и там есть только PostgreSQL. Если вы не использовали класс абстрактного доступа к базам данных, то вам пришлось бы:

  • заменить весь код работы с mysql на postgresql
  • переписать SQL-запросы (так как есть отличия)

Если бы вы использовали абстрактный слой доступа к БД, то вам скорее всего не пришлось бы менять php-код (только в одном месте указали бы что используете postgresql) и изменить SQL-запросы (хотя иногда и это не понадобилось бы).
Я намеренно в этом описании использовал фразу "абстрактный класс доступа к БД",
поскольку ADODB — не единственный подобный класс. Наиболее известные конкуренты:

  • Pear::DB
  • Pear::MDB

Насколько я знаю, другие классы имеют слабую функциональность, хотя должен признать, работают быстрее. Многие пишут такие классы сами, но я не сторонник изобретения велосипедов.
Противники таких массивных классов, как ADODB или Pear::DB утверждают, что их использование плохо сказывается на производительнеости. Да, производительность падает и это вполне логично. НО:

  • Скорость не часто является самым важным фактором
    (Мало кто из вас пишет сайты с очень большой нагрузкой, на которых бы это снижение производительности стало критичным)
  • Использование таких классов повышает производительность программиста
  • При использовании софта, типа phpAccelerator падение производительности будет не таким заметным (и я не поверю, что популярные сайты не имеют возможности использовать такой софт)
  • Разработчики ADODB написали php-extension, который ускоряет работу класса (но работать можно и без него)

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

 

3. Простые примеры

Пример 1


<?php
// подключаем класс 
include_once("adodb/adodb.inc.php");

// указываем тип БД
$conn = &ADONewConnection(\'mysql\');
// соединяемся с БД
$conn->Connect(\'localhost\', \'root\', \'password\', \'scripts\');
// режим отладки&nbsp;&#151; включен (true)
$conn->debug = true;
$conn->setFetchMode(ADODB_FETCH_ASSOC);
?>&lt;/php>

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


<?php $conn = &ADONewConnection(\'mysql\'); ?>

Создается объект соединения с базой данных. Именно через поля и методы данного объекта и будет в дальнейшем вестись работа с базой данных.
Что касается режима отладки, то по умолчанию он выключен. При включенном режиме отладки на экран броузера будут выводиться SQL-запросы и тексты ошибок (если такие были). Очень упрощает процесс написания и отладки скриптов.
Метод $conn->setFetchMode() — указывает, каким образом данные о записях будут записаны в массив — будет ли это ассоциативный массив, или простой нумерованный или и тот и другой. Ей нужно установить одно из значений (0, 1, 2, 3). Для пояснений приведу код из исходников adodb:


<?php   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
Теперь сделаем запрос к БД:


<?php
// делаем запрос к БД
$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() — может быть использован для любых запросов:


<?php
// делаем вставку строки
$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 работают функции для постраничной выборки:


<?php
// определяем текущую страницу
$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 запросов

Для начала пример:


<?php
// пример генерировани 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 Работа с транзакциями

Ну это вообще сказка :). Вот пример из мануала:


<?php
   $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 эмулирует эту возможность почти для всех СУБД. На практике это выглядит примерно так:


<?php
   $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 поддерживает серверное кеширование запросов. Суть в том, что при первом выполнении запроса его результаты заносятся в кеш-файл. При последующем таком же запросе (если кеш-файл не устарел) данные будут браться из файла.
Честно говоря, мне не нравится метод, которым они производят кеширование (по-моему они слишком уж универсальным сделали его) и предпочитаю делать кеширование своими руками.
Если вас все-таки интересует кеширование, то работает оно так:


<?php
   $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(24*3500, \'SELECT * FROM tab\');
?>

4.6 Статистика запросов.

Наверное видели на некоторых сайтах выводится статистика:
Страница сгенерирована за 0.0016 секунд. Запросов к базе данных — 12
Как вычисляется время генерирования страницы — к данной статье не относится, а вот посчитать количество запросов к БД (а также посчитать количество запросов, взятых из кеша) ADODB позволяет:


<?php
// пример взят из мануала
function CountExecs($conn, $sql, $inputarray) {
   global $EXECS;
   $EXECS++;
}

function CountCachedExecs($conn, $secs2cache, $sql, $inputarray) {
   global $CACHED;
   $CACHED++;
}

$conn = NewADOConnection(\'mysql\');
$conn->Connect(...);
$conn->fnExecute = \'CountExecs\';
$conn->fnCacheExecute = \'CountCachedExecs\';

...
// выводим статистику
echo "Всего запросов к базе данных: <b>".$EXECS+$CACHED."</b><br />";
echo "Из них взято из кеша : <b>".$CACHED."</b>";
?>

Данные функции вызываются до запроса, поэтому вы можете с их помощью переписать SQL-запрос.

5. ADODB & PEAR

Я являюсь фанатом как adodb так и репозитария PEAR.
К сожалению основным классом работы с базами данных в PEAR является PEAR::DB
И многие PEAR-классы используют его. Что же делать любителям adodb?
Во-первых, если хорошо присмотреться, то классов, использующих PEAR::DB не так уж и много. У меня почти весь pear-репозитарий на компьютере и там pear::DB используют лишь

  • DB::NestedSet
  • DB::DataObject
  • DB::Pager
  • DB::QueryTool
  • HTML::Select
  • XML::sql2xml
  • Auth
  • Cache
  • Log
  • LiveUser
  • Mail::Queue
  • Translation

Во-вторых, многие классы использую "контейнеры", и для этих классов можно написать контейнер, использующий ADODB (как писать контейнеры — смотрите на примере контейнеров pear::DB указанных классов).
В-третьих, ADODB имеет файл adodb-pear.inc.php который является эмуляцией класса PEAR::DB и остальные классы можно подогнать под работу с adodb с минимальными телодвижениями (часто достаточно в тексте класса строку     require_once(\'DB.php\'); заменить на     require_once(\'adodb-pear.inc.php\'); но так бывает не всегда).
Так что ADODB можно успешно применять с pear-классами. Приведу пример использования adodb c классом pear::XML::sql2xml. Для тех кто не в курсе — этот класс трансформирует результат запроса (SELECT) к БД в XML-строку:


<?php
require_once("adodb/adodb-pear.inc.php");
require_once("XML/sql2xml.php");

$db = DB::connect("mysql://root@localhost/lot");
$sql2xml = new xml_sql2xml();                       
$result = $db->getAll("select * from lot_sessions");        
$xmlstring = $sql2xml->getXML($result);
?>

Те кто уже имеют опыт работы с XML_sql2xml наверное чаще применяют код, который предлагает автор класса XML_sql2xml:


<?php
require_once("XML/sql2xml.php");
$sql2xml = new xml_sql2xml("mysql://root@localhost/lot");
$sql2xml->Add("select * from lot_sessions");                        
$xmlstring = $sql2xml->getXML();
?>

и


<?php
$db = DB::connect("mysql://root@localhost/lot");
$sql2xml = new xml_sql2xml();                       
$result = $db->query("select * from lot_sessions");
$xmlstring = $sql2xml->getXML($result);
?>

Оба эти примера не сработают и нужно будет править класс XML_sql2xml.

Услуги
Портфолио
BTL инфо
Администрирование
 
Дизайн
 
Программирование
 
htlm/dhtml
javascript
ajax
aps
flash action script
php
xhtml/wap
database
Поисковая оптимизация и раскрутка
 
Шаблоны
 
Программы
 
Контакты

УКР РУС ENG

  © 2005-2008 дизайн-студия myua.com.ua