Использование DBI
Вот что следует делать для использования DBI. Информацию о самом DBI можно найти в книге «Programming the Perl DBI» Аллигатора Декарта (Alligator Descartes) и Тима Банса (Tim Bunce) (O'Reilly).
Шаг 1: Загрузите нужный модуль
Здесь нет ничего особенного, нужно лишь написать:
use DBI;
Шаг 2: Соединитесь с базой данных и получите дескриптор соединения
Код на Perl, устанавливающий DBI-соединение с базой данных MySQL и возвращающий дескриптор базы данных, выглядит примерно так:
соединиться с базой данных $database используя заданное имя
Sdatabas
$dbh = DBI-->comect("D8I:nysal :Sdatabase Saseriare $pw);
die "Онибка Н-'-юзмолно соединиться:
$dbh);
До соединения с сервером DBI загрузит низкоуровневый DBD-драйвер (DBD: :^ysc:!). Перед тем как двигаться дальше, проверим, что соединение (при помощи con пес: ()) установлено. DBI предоставляет два параметра для connect () - Raise-Error и Print Er , определяющие, будет ли DBI выполнять эту проверку или сообщит об ошибках, когда они возникнут. В частности, если применить:
$dbh = DBI->connect("DBI:mysql:$database",
$username,$pw,{RaiseError =
то DBI вызовет die, при условии, что соединение с базой данных не произошло.
Шаг 3: Отправьте команды SQL-серверу
Когда модуль загружен и соединение с сервером баз данных установлено, начинается самое интересное. Пошлем серверу несколько SQL-команд. Мы будем использовать запросы, приведенные в качестве примеров из приложения D. В этих запросах для заключения в кавычки применяется оператор q (т. e. something записывается как q{something}), следовательно, не нужно беспокоиться о кавычках внутри запросов. Вот первый из двух DBI-методов, существующих для отправки команд:
$results=$dbh->do(q{UPDATE hosts
SET bldg = 'Main'
WHERE name = 'bendir'});
die "Невозможно выполнить обновление:
$DBI: :errstr\n" unless (define;; Sresults);
Переменная Sresuits равна либо количеству обновленных записей, либо uricief, если произошла ошибка. И хотя важно знать, сколько записей было обработано, такой метод абсолютно не подходит для операторов, подобных SELECT, где необходимо увидеть сами данные. Следовательно, нужно применить второй метод.
Для использования второго метода необходимо сначала подготовить оператор SQL (с помощью команды оч-иге), а затем выполнить (execute) его на сервере.
Команда рrераrе() возвращает нечто новое, чего мы раньше никогда не встречали: дескриптор команды. Так же, как дескриптор базы данных ссылается на открытое соединение с базой данных, дескриптор команды ссылается на конкретный SQL-оператор, который был подготовлен с помощью р"есагс(). Получив дескриптор команды, можно использовать exucir.u для отправки запроса на сервер. Позже подобный дескриптор команды будет применяться для получения результатов запроса.
Вероятно, вас удивляет, зачем сначала подготавливать оператор, вместо того чтобы напрямую выполнить его. Подобная операция позволяет драйверу DBD (или, что более вероятно, вызываемой библиотеке) выполнить синтаксический разбор SQL-запроса. После того как оператор подготовлен, можно повторно выполнить его через дескриптор команды, не проводя больше синтаксический анализ. Зачастую это основной фактор повышения эффективности. В действительности, DBI-метод do(), используемый по умолчанию, для каждой выполняемой команды применяет сначала рrераrе(), а затем execute().
Как и вызов do, рассмотренный ранее, метод execute() возвращает количество обработанных записей. Если результатом запроса является ноль записей, возвращается строка ОЕО, эта строка при логической проверке воспримется как «истина». Если драйверу неизвестно, сколько записей было обработано, возвращается -1.
Перед тем как перейти к ODBC, стоит упомянуть еще об одной особенности prepared), поддерживаемой большинством DBD-модулей, а именно о заполнителях (placeholders). Заполнители, также называемые позиционными маркерами, позволяют подготовить команду с оставленными в ней «дырами», в которые можно внести значения во время выполнения команды (executeO). Подобное свойство помогает конструировать запросы на лету, не затрачивая лишнего времени на их синтаксический разбор. Знак вопроса используется как заполнитель для одного скалярного значения. Вот пример кода на Perl, демонстрирующий такое применение заполнителей:
©machines = qw(bendir shimmer sander);
$sth = $dbh->prepare(q{SELECT nair.e, ipaddr FROM hosts WHERE naire = 9}):
foreach Sname (&machines){ $sth->execute($narr.e):
Каждый раз, проходя через цикл гегемон, запрос SELECT выполняется с разными условиями WHERE. Можно применять и несколько заполнителей:
$str->prepare;
q{SELECT ria.T.o :nad''!" f ROM t ou's WHERE (name = ? AND bldg = ? AND dept = ?)}):
$sth->execute($nan-!0t $bldg, Sdept);
Теперь, когда известно, как получить количество записей, обрабатываемых запросом, отличным от SELECT, посмотрим, как получить результаты запросов SELECT.
Шаг 4: Получите результаты запроса SELECT
Механизм, рассмотренный здесь, похож на историю о курсорах из приложения D. Когда серверу при помощи execi::p() посылается запрос SELECT, применяется способ, позволяющий возвращать результаты построчно.
Для получения данных в DBI используется один из методов, перечисленных в табл. 7.1.
Таблица 7.1. DBI-методы получения данных
Имя |
Возвращает |
Возвращает, если больше нет записей |
fetchrow_arrayref ( ) |
Ссылка на анонимный массив со значениями, являющимися полями следующей записи |
undef |
fetchrow_array() |
Массив со значениями, являющимися полями следующей записи |
Пустой список |
fetchrow_hashref ( ) |
Ссылка на анонимный хэш, ключами которого являются имена полей, а значениями - значения полей следующей записи |
undef |
fetchall_arrayref () |
Ссылка на массив массивов |
Ссылка на пустой массив |
$sth = $dbh->prepare(q{SELECT name,ipaddr,dept from nosts}) or
die "Невозможно подготовить запрос: ".$dbh->errstr." \n":
$sth->execute or die "Невозможно выполнить запрос: ". $dbh-->orr
Вот метод fetchrow_arrayref () в действии:
while (Saref = $sth->fetchrow_arrayref){ print "name: " .
$aref~>[0] . "\n"; print "ipaddr: " . $aref->[1] . "\n";
print "dept: " . $aref->[2] . "\n":
А теперь рассмотрим «удобный» метод fe*chall_array"of (). Он загружает весь полученный результат в одну структуру данных, возвращая ссылку на массив ссылок. При использовании данного метода будьте осторожны и учитывайте размер запросов, поскольку результаты целиком считываются в память. Если размер результата равен 100 Гбайт, это может вызвать проблемы.
Каждая ссылка выглядит точно так же, как и результат вызова метода fetchrow_an ayref ().
Вот какой код выводит результат запроса целиком:
$aref_aref = $sth->fetchall_arrayref;
foreach $rowref (@$aref_aref){
print "name: " . $rowref->[0] . "\n";
print "ipaddr: " . $rowref->[1] . "\n";
print "dept: " . $rowref->[2] . "\n";
print '-'x30."\n": }
Этот пример применим только к конкретному набору данных, поскольку предполагается, что количество полей фиксировано и они следуют в определенном порядке. Например, считается, что имя машины возвращается в первом поле запроса ($rowref->[0]).
Можно переписать предыдущий пример и сделать его более общим, если использовать атрибуты (часто называемые метаданными) дескриптора команды. В частности, если после запроса посмореть на $sth->{NUM_OF_FIELDS}, то можно узнать количество полей в полученных данных. $sth->{NAME} содержит ссылку на массив названий полей.
Обязательно изучите документацию по DBI, чтобы подробно узнать об остальных метаданных.
Шаг 5: Закройте соединение с сервером
С DBI это очень просто сделать:
сообщаем серверу, что данные из дескриптора команды больше
и не нужны (необязательно, т. к. мы собираемся завершить
# соединение)
$sth->finish;
ft разорвать соединение дескриптора с базой данных
$dbh->disconnect;
Что еще надо сказать о DBI
Осталось еще две темы, которые стоит обсудить, прежде чем переходить к ODBC. Во-первых, это набор методов, которые я называю «удобными» (shortcut methods). Методы, приведенные в табл. 7.2, объединяют перечисленные шаги 3 и 4.
Таблица 7.2. Удобные методы DBI
Название |
Объединяет в себе следующие методы |
select row_a r ray ref (Sstmnt) |
prepare(Sstmnt), execute( ), fetchrow_arrayref ( ) |
selectcol_arrayref ($stmnt) |
prepare($stmnt), execute( ), (@{fetchrow_arrayref()})[0] (т. е. возвращает первое поле для каждой записи) |
select rowar ray (Sstmnt) |
prepare(Sstmnt), execute( ), fetchrow_array( ) |
die "Невозможно выполнить запрос:".$dbh~>errstr" \n";
К эти переменные получат 1-й, 2-й и 3-й столбы из SELECT
$rc = $sth->Pind_columns(\$name, \$ipaddr, \$dept):
while ($sth->fetchrow_arrayref){
tt
$name, Sipaddr и $dept автоматически получают значения из
tt
результатов запроса