SELECT (обучающий этап) задачи по SQL запросам 120 штук, DML 10 шт. Дистанционное обучение языку баз данных SQL. Интерактивные упражнения и тестирование по операторам SELECT,INSERT,UPDATE,DELETE языка SQL. SQL remote education. SQL statements exercises. Подзапросы, Соединение таблиц, Функции SQL, Введение в SQL, Скачать книги по SQL. Команды SQL,CREATE SEQUENCE,CREATE SYNONYM,CREATE USER,CREATE VIEW,Create Table,DROP,GRANT,INSERT,REVOKE,SET ROLE,SET TRANSACTION,SQL ALTER TABLE,SQL команды.
понедельник, 28 января 2019 г.
Абстрактный доступ к БД с помощью ADODB
Абстрактный доступ к БД с помощью ADODB
Автор: Maxim Matyukhin
Подробное описание абстрактного класса баз данных ADODB. Установка, примеры использования, особенности, ADODB & PEAR.
1. Пару слов об ADODB 2. Установка 3. Простые примеры 4. Практическое использование
4.1 Постраничный вывод и ограничение SELECT-запросов 4.2 Генерирование INSERT/UPDATE запросов 4.3 Работа с транзакциями 4.4 Последовательности 4.5 Кеширование запросов 4.6 Статистика запросов
5. ADODB & PEAR 6. Заключение
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 и проблем с производительностью не имеют.
Можете еще скачать и php-extension, но я его использовать не пробовал. Чтобы использовать класс, вам необходимо включить (include) файл ./adodb/adodb.inc.php
3. Простые примеры
Пример 1
<?php // подключаем класс include_once("adodb/adodb.inc.php"); // указываем тип БД $conn = &ADONewConnection('mysql'); // соединяемся с БД $conn->Connect('localhost', 'root', 'password', 'scripts'); // режим отладки — включен (true) $conn->debug = true; $conn->setFetchMode(ADODB_FETCH_ASSOC); ?></php>
Данный пример демонстрирует подключение к БД. В строке
<?php $conn = &ADONewConnection('mysql'); ?>
Создается объект соединения с базой данных. Именно через поля и методы данного объекта и будет в дальнейшем вестись работа с базой данных.
Что касается режима отладки, то по умолчанию он выключен. При включенном режиме отладки на экран броузера будут выводиться SQL-запросы и тексты ошибок (если такие были). Очень упрощает процесс написания и отладки скриптов.
Метод $conn->setFetchMode() — указывает, каким образом данные о записях будут записаны в массив — будет ли это ассоциативный массив, или простой нумерованный или и тот и другой. Ей нужно установить одно из значений (0, 1, 2, 3). Для пояснений приведу код из исходников adodb:
Судя по исходникам 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:
ВЫБРАТЬ * ИЗ ВСТАВКИ LIMIT 0, 10
PostgreSQL:
ВЫБРАТЬ * ОТ вкладки OFFSET 0, LIMIT 10
FireBird:
ВЫБЕРИТЕ ПЕРВЫЙ 10 ПРОПУСТИТЬ 0 * ОТ вкладки
Класс 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->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 эмулирует эту возможность почти для всех СУБД. На практике это выглядит примерно так:
Метод $conn->GenID() создает последовательность site_users (если она до этого не была создана) и возвращает значение на единицу больше чем текущее значение последовательности.
4.5 Кеширование запросов
ADODB поддерживает серверное кеширование запросов. Суть в том, что при первом выполнении запроса его результаты заносятся в кеш-файл. При последующем таком же запросе (если кеш-файл не устарел) данные будут браться из файла.
Честно говоря, мне не нравится метод, которым они производят кеширование (по-моему они слишком уж универсальным сделали его) и предпочитаю делать кеширование своими руками.
Если вас все-таки интересует кеширование, то работает оно так:
По умолчанию время жизни кеш-файлов — 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::DB
И многие PEAR-классы используют его. Что же делать любителям adodb?
Во-первых, если хорошо присмотреться, то классов, использующих PEAR::DB не так уж и много. У меня почти весь pear-репозитарий на компьютере и там pear::DB используют лишь
DB :: NestedSet
DB :: DataObject
DB :: Пейджер
DB :: QueryTool
HTML :: Выбрать
XML :: SQL2XML
Auth
кэш
Журнал
LiveUser
Mail :: Tail
Перевод
Во-вторых, многие классы использую "контейнеры", и для этих классов можно написать контейнер, использующий 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.
6. Заключение
Поскольку статья носит ознакомительный характер, многое осталось "за кадром". Я не пытался описать все классы, поля и методы — для этого есть официальная документация. Также я не описывал функциональные возможности, которые не использовал на практике:
хранение сессий в БД (в том числе и зашифрованных сессий)
работа с хранимыми процедурами
работа с БД, находящейся на удаленном сервере
словари (позволяют программно создавать базы данных и таблицы)