Глава
№11.
Python
Если вы пишете
много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться
с ним. Python является объектно-ориентированным языком сценариев, сочетающим
мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать
приложения, которые легко поддерживать и развивать. Отличное введение в программирование
на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher)
«Learning Python», изданной O'Reilly & Associates, Inc.
В данной главе предполагается наличие у читателя знакомства с основами языка
Python, включая умение добавлять новые модули к начальной инсталляции Python.
Поддержка
баз данных MySQL и mSQL со стороны Python, которая является предметом данной
главы, осуществляется посредством двух модулей Python. В момент публикации данной
книги модуль для mSQL был доступен на http://www.python.org,
а для MySQL - на http://www.mysql.com. Хотя
есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL
и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для
MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров
этой главы необходимо установить один или оба этих модуля.
Оба API практически
одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где
между ними есть различия.
Основы
подключения к базам данных
API для Python
являются, вероятно, самыми простыми API для работы с базами данных из всех,
встречающихся в этой книге. Как и для других API, начать нужно с подключения
к базам данных — установления соединения. Поскольку Python имеет интерактивный
интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора
командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение
с базами данных MySQL и mSQL соответственно. В первом примере производится соединение
с базой данных MySQL:
[4:30pm] athens>
python
Python 1.5.1
(#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5
Copyright 1991-1995
Stichting Mathematisch Centrum, Amsterdam
>>>
import MySQL;
>>>
db = MySQL.connect( 'athens. imaginary.com');
>>>
db.selectdb('db_test');
>>>
result = db.do('select test_val from test where test_id = 1');
>>>
print result;
[['This is a
MySQL test.']]
>>>
Код для mSQL,
делающий то же самое, выглядит почти идентично:
[4:30pm] athens>
python
Python 1.5.1
(#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5
Copyright 1991-1995
Stichting Mathematisch Centrum, Amsterdam
>>>
import mSQL;
>>>
db = mSQL.connect('athens. imaginary.com');
>>>
db.selectdb('db_test');
>>>
result = db.query('select test_val from test where test_id = 1');
>>>
print result;
[('This is a
mSQL test.',)]
>>>
В обоих случаях
прежде всего нужно импортировать соответствующий модуль Python. He следует использовать
синтаксис mSQL import *, так как он засорит пространство имен вашего приложения.
Вместо этого в каждом модуле следует получить экземпляр описателя базы данных
с помощью метода connect() и использовать этот описатель для доступа к базе
данных.
Вызов connect()
в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL
мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку
в этом случае не требуется указания имени пользователя или пароля, вызов connect()
для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать
имя пользователя и пароль, если того требует ваша база данных MySQL. Например,
db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит
вас к серверу MySQL на athens.imagi-nary.com в качестве «myuid»
с паролем «password». Тот и другой API не требуют имени узла при
локальном подключении. В этом случае они достаточно сообразительны и для более
быстрого соединения используют сокет домена Unix (на Unix-системах).
Процесс соединения
в С API является двухэтапным и требует сначала соединиться с сервером, а затем
выбрать базу данных, которую вы хотите использовать. Для API Python требуются
те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически
одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный
параметр - имя базы данных. MySQL поддерживает необязательный второй параметр,
позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока
не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда
вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий
набор.
Запросы
Эти два API
слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются
возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров.
Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный
набор методов API, которые более точно отражают С API и обеспечивают поддержку
курсоров. При программировании на Python поддержка курсоров имеет сомнительную
ценность, поскольку ни одна из этих баз данных не поддерживает редактирование
по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться
вперед и назад по результирующему набору с такой же легкостью, как и с помощью
курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку
метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического
доступа к базе данных.
mSQL API
и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить
результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное
различие в том, каким образом это делается. Во-первых, для mSQL метод запроса
называется query(), а для MySQL он называется do(). Каждый из методов воспринимает
в качестве аргумента любую строку SQL. Если команда порождает результирующий
набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков
для MySQL.
В большинстве
случаев различие в типе возвращаемых значений несущественно: кортежи не могут
изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить,
что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если
вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится
простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая
результаты.
Пример
11-1. Обработка запросов в Python дд,я mSQL и MySQL
#!\/usr/local/bin/python
# Импорт модулей
import Msql, MySQL;
# Инициализация
значений database и query
database = 'db_test';
query = 'SELECT
test_id, test_val FROM test';
# Соединение с серверами msql = mSQL.connect();
mysql = MySQL.connect();
# Выбор тестовых баз данных msql.selectdb(database);
mysql.selectdb(database);
# Выполнение запроса
m_result = msql.query(query);
my_result = mysql.do(query);
#Обработка результатов для mSQL
for row in m_result:
# Здесь row
является кортежем
print "mSQL-
test_id: ",row[0]," test_val: ",row[1];
# Обработка результатов для MySQL
for row in my_result:
ft Здесь row
является списком
print "MySQL-
test_id: ",row[0]," | test_val: ",row[1];
# Закрыть соединение (только mSQL)
msql.close();
Для обеих
баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего
набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую
колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент
в списке MySQL представляет первую колонку запроса, а второй элемент - вторую
колонку.
Обновление
Обновление,
вставка и удаление в базе данных производится с помощью того же метода API,
что и запросы, - просто не требуется обрабатывать результирующий набор. Иными
словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть
дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой
таблице есть поле с атрибутом AUTO_INCREMENT .
Динамическое
соединение с базами данных
Тот метод
API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое
для простых и наиболее часто встречающихся повседневных задач выборки, вставки,
обновления и удаления данных в базе. В некоторых более сложных приложениях может
оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой
соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные
уровня базы данных - информацию времени выполнения о базе данных, с которой
соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых
вызовов SQL, включая метаданные результирующего набора.
Описатели
команд в MySQL
Как уже отмечалось,
в MySQL есть два средства обработки запросов. Более простая форма возвращает
результирующий набор в виде списка списков. Более сложная форма возвращает описатель
команды.
Описатель
команды представляет результаты обработки запроса к MySQL через метод query()
(в противоположность использованию метода do()). Пример 11-2 показывает, как
можно использовать описатель команды для получения информации времени выполнения
о запросе или команде обновления.
Пример
11-2. Динамический доступ к базе данных MySQL с помощью описателя команды
[7:20pm] athens>
python
Python 1.5.1
(#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5
Copyright 1991-1995
Stichting Mathematisch Centrum, Amsterdam
>>>
import MySQL;
>>>
db = MySQL,con.nect();
>>>
db.selectdb('db_test-);
>>>
result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,
'Bing!')");
>>>
print result.affectedrows();
1
>>>
result = db.query("SELECT * FROM test");
>>>
print result. numrows();
3
>>>
print result.fields();
[['test_id',
'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',
100, "]]
>>>
print result, fetchrows(-l);
[[1, 'This is
a test.'], [2, 'This is a test.'], [4. 'Bing!']]
>>>
В дополнение
к результирующему набору запроса можно с помощью описателя команды получить
число строк, затронутых операциями обновления, вставки или удаления. В примере
11-2 мы получили количество строк, возвращенных запросом, и подробные сведения
о колонках, представленных в результирующем наборе.
Из новых
методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным.
Этот метод получает очередную группу строк в количестве, определяемом переданным
ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается
список, состоящий из очередных двух строк. Метод возвращает список, состоящий
из всех строк, если ему передан параметр, меньший 0 — как в данном примере.
Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему
набору. Метод seek() принимает целочисленный параметр, указывающий на строку,
с которой вы хотите работать, при этом 0 указывает на первую строку.
Метаданные
базы данных
Хотя только
MySQL API поддерживает динамическое управление результирующим набором (по крайней
мере, на момент данной публикации), оба API поддерживают метаданные базы данных
с помощью почти идентичных наборов методов. Метаданные базы данных представляют
собой информацию о соединении с базой данных. В примере 11-3 приведена сессия
Python, заставляющая соединения с MySQL и mSQL рассказать о себе.
Пример
11-3. Данные
[7:56pm] athens>
python
Python 1.5.1
(#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5
Copyright 1991-1995
Stichting Mathematisch Centrum, Amsterdam
>>>
import mSQL, MySQL;
>>>
msql = mSQL.connect();
>>>
mysql = MySQL.connect();
>>>
print msql.listdbs();
['db_test',
'db_web']
>>>
print mysql.listdbs();
[['dbjest'],
['mysql'], ['test']]
>>>
msql.selectdb('db_test');
>>>
mysql.selectdb('db_test');
>>>
print msql. listtables();
['test', 'hosts']
>>>
print mysql.listtables();
[['test']]
>>>
print msql.serverinfo;
2.0.1
>>>
print mysql.serverinfo();
3.21.17a-beta-log
>>>
print mysql.clientinfo();
MySQL-Python-1.1
>>>
print msql.hostname;
None
>>>
print mysql.hostinfo();
Localhost via
UNIX socket
>>>
print mysql.stat();
Uptime: 4868410
Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4
>>>
print mysql.listprocesses();
None
>>>
В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III «Справочник» за полным описанием этих методов и атрибутов.