Работа с базами данных из Perl. Краткое введение в DBI
В настоящее время практически невозможно найти область
применения, в которой бы не использовались базы данных. Для Web базы данных
играют очень важную роль, позволяя создавать интернет-магазины, ленты новостей,
сайты банков, и т.п.
Для этих целей в Perl существует множество различных модулей,
которые оптимизованы для работы с конкретными типами баз данных. Но как правило
эти модули имеют разные наборы функций для работы с базами. Для упрощения
переноса приложений был разработан модуль
DBI. Он
построен по модульной архитектуре -- для каждой СУБД существует драйвер,
реализующий специфику работы с конкретной базой данных. Сначала мы рассмотрим
основные функции работы с базами данных, а затем перейдем к практическому
примеру применения DBI.
Общий алгоритм работы с базой данных можно представить в
следующем виде:
Подключение к базе данных с помощью функции connect
Подготовка запроса к выполнению с помощью функции
prepare
Выполнение запроса с помощью функции execute
Выборка данных (для запросов содержащих команду SQL
select) с помощью функций fetch
Завершение работы с базой данных -- функции finish
и disconnect
Подключение к базе данных
Для работы необходимо подключить модуль DBI к вашему
скрипту. Это осуществляется с помощью директивы use DBI.
Затем необходимо выполнить подключение к базе данных с
помощью вызова функции connect. При этом функции передается строка,
описывающая базу данных, имя пользователя, пароль и атрибуты, управляющие
обработкой ошибкой и т.п. Вот пример:
my $dbh=DBI->connect("dbi:Pg:dbname=dbase;host=localhost;port=5432",
"user","pass");
В данном примере производится подключение к базе dbase
при помощи драйвера PostgreSQL. Подключение производится под именем пользователя
user с паролем pass. При удачном подключении функция
возвращает дескриптор базы данных, который часто обозначают как $dbh.
Дальнейшая работа с базой данных осуществляется через этот дескриптор.
Выполнение SQL-выражений
Для выполнения SQL-выражений в DBI существует два метода --
использование цепочки prepare, execute; и функция do.
Функция do в основном используется для выполнения
выражений, не возвращающих наборов данных, такие как insert, update
и delete. В качестве результата возвращается количество строк,
затронутых данным выражением. Данная функция применяется к дескриптору базы
данных. Вот пример использования:
$rv = $dbh->do("delete from test1 where id <20");
Набор функций prepare, execute чаще
используется для выполнения выражений select, которые возвращают наборы
данных. Для начала работы необходимо создать с помощью функции prepare
дескриптор выражения. Данный дескриптор можно использовать для выполнения
выражения с разными данными. Выполнение самого выражения производится с помощью
функции execute для дескриптора выражения. При выполнении этой функции,
параметры, обозначенные в SQL-выражении знаком вопроса ?, заменяются на
параметры, переданные функции execute. При успешном выполнении функции
возвращается истинное значение. После выполнения функции можно получать данные.
Получение результатов
После выполнения SQL-выражения мы можем получать не только
данные, но и некоторую информацию о выполненном запросе. Некоторые драйвера
поддерживают функцию row, которая возвращает количество строк,
извлеченных запросом. Можно также получить информацию о типе и длине полей
строк, возвращаемых после выполнения запроса.
Для получения строки данных может использоваться функция
fetchrow_array, которая возвращает список, состоящий из данных возвращенных
SQL-выражением. Альтернативами данной функции могут быть функции
fetchrow_arrayref и fetchrow_hashref, которые возвращают ссылки на
массив или ассоциативный массив, хранящий результаты. При использовании
ассоциативного списка, выполняется дополнительная работа по созданию пар "ИМЯ
ПОЛЯ=ЗНАЧЕНИЕ".
Для извлечения всех данных данной выборки используются
функции fetchall_arrayref и fetchall_hashref. В первом случае
возвращается ссылка на массив ссылок на строки данных, а во втором ссылка на
ассоциативный массив, ключом которого является указанное в качестве параметра
поле. При вызове fetchall_arrayref можно указать какие колонки данных
могут быть включены в результат, при этом можно указывать как имена полей в
выборке, так и номера необходимых полей.
Транзакции
Вы можете явно управлять транзакциями с помощью функций DBI.
По умолчанию действует режим, когда все действия автоматически подтверждаются.
Функция begin_work начинает новую транзакцию, отключая режим
автоматического подтверждения выражений. Если драйвер не поддерживает концепцию
транзакций, то возвращается ошибка. Функции commit и rollback
соответственно подтверждают или отменяют выполненные выражения. Все эти функции
применяются к дескриптору базы данных.
Завершение работы
В некоторых случаях после окончания извлечения данных,
возвращенных запросом, для дескриптора выражения рекомендуется выполнить функцию
finish. Обычно драйвер автоматически вызывает эту функцию при
извлечении всех данных.
При завершении работы с базой данных вы должны для
дескриптора базы данных вызвать функцию disconnect. Обычно она
вызывается перед завершением работы с программой. Поведение в отношении
транзакций является неопределенным. Некоторые драйвера автоматически
подтверждают изменения, а некоторые автоматически отменяют их. Так что будьте
осторожны.
Практический пример
Давайте рассмотрим процедуру, которая производит извлечение
ленты новостей из базы данных. Новости хранятся в базе данных news
и разбиты на несколько категорий, список которых хранится в другой таблице.
Кроме этого производится доступ к таблице users, хранящей данные о
пользователях, которые помещают новости. Новости разбиваются на страницы по 20
новостей на страницу.
Вот полный текст процедуры, который будет описан далее:
1 sub BuildNewsPage {
2 my ($cat,$id)=@_;
3 my %params;
4 my $dbh = DBI->connect("dbi:Pg:dbname=news;host=localhost;port=5432",
5 "news", "test", { RaiseError => 0, AutoCommit => 1 });
6 if (!defined($dbh)) {
7 $params{Error}='Hе могу откpыть базу данных';
8 } else {
9 my $where="and catid=";
10 my $cattext="";
11 my %cats=GetNewsCategories($r);
12 $cat='1' if !defined($cat);
13 if (defined($cat)) {
14 $where.=$cat;
15 $cattext=$cats{$cat}->{title};
16 }
17 if (lc($cat) eq 'all'){
18 $where="";
19 $cattext="Все новости";
20 }
21 $where.="and n.id < $id" if defined($id);
22 my $sql="select n.id, data::date, n.sender, u.fullname, n.news,
23 n.moreinfo from news n, users u where n.sender=u.login
24 $where order by n.id desc limit 20";
25 my $sth = $dbh->prepare($sql);
26 if ( !defined($sth) ) {
27 $params{Error}='Hе могу выполнить запpос к базе новостей';
28 } else {
29 $sth->execute();
30 my @news=();
31 while (my ($id, $data, $login, $sender, $news, $moreinfo) = $sth->fetchrow_array()) {
32 my %t1;
33 $t1{sender}=$sender;
34 $t1{login}=$login;
35 $t1{id}=$id;
36 $t1{newstitle}=$news;
37 $t1{newsbody}=$moreinfo;
38 $t1{date}=$data;
39 push @news,\%t1;
40 }
41 $sth->finish();
42 $dbh->disconnect if defined($dbh);
43 $params{news}=@news;
44 }
45 }
46 return %params ;
47 }
Процедуре передается два параметра $cat --
категория новостей и $id -- идентификатор новости с которой надо
начать выборку (в том случае, если мы показываем вторую и последующие страницу
новостей. Хеш %params будет хранить в себе сообщения об ошибках и
данные, для заполнения шаблона страницы.
В строках 4-7 мы подключаемся к базе данных PostgreSQL
(драйвер базы данных называется Pg) и выполняется проверка того,
как произошло подключение. Если произошла ошибка подключения, то мы помещаем
соответствующее сообщение в хеш %params. Сообщения об ошибках
выдаются вызывающей процедурой, которая также заполняет шаблон страницы.
В строках 9-21 формируется условие для SQL выражения, которое
ограничивает набор отображаемых новостей. Если номер категории не задан, то
отображаются новости категории 1 (главные новости).
Затем в строках 22-27 формируется текст запроса и выполняется
подготовка к выполнению запроса. Если функция prepare возвратит
неопределенное значение, то мы сообщаем об ошибке (строки 26-27).
В строках 29-40 производится выполнение запроса и извлечение
данных с помощью функции fetchrow_array. Для каждой из извлеченной
строк формируется отдельный хеш, который помещается в массив новостей.
После извлечения всех новостей, запрос закрывается и
производится отключение от базы данных (строки 41-42). И в заключение
сформированный хеш с результатами работы возвращается вызывающей программе,
которая производит формирование страницы для пользователя.
Заключение
Самой лучшей документацией по модулю DBI является его
справочная страница доступная с помощью программ perldoc и man.
Также на русский язык переведена книга Perl DBI Programming. Кроме
описания работы с модулем DBI, данная книга представляет краткое введение в язык
структурированных запросов SQL, а также описание других методов хранения
информации, возможных при работе с Perl.
DBI эффективно интегрируется с другими модулями, такими как
например модули из поставки mod_perl, которые позволяют кэшировать
соединения с базами данных, использовать базы данных для аутентификации и
авторизации.
Одним из популярнейших вопросов во всевозможных форумах является вопрос «Как загрузить файл на сервер?». А ведь на самом деле это не так сложно, как кажется на первый взгляд. И чтобы не было совсем легко – пусть скрипт, который приведен ниже еще и посылает этот файл по почте, в виде вложения... подробнее
В статье рассматривается один из основных подходов к генерации динамического контента в среде веб-приложений, а именно использование веб-сценариев и CGI, и применительно к ним, методы защиты исходных текстов от несанкционированного копирования и модификации... подробнее