Сообщить об ошибке.

Реализация интерфейса MySQL C API в модуле MySQLdb Python

Руководство по работе с интерфейсом API C MySQL на Python

Подмодуль MySQLdb._mysql предоставляет интерфейс, который в основном реализует API MySQL для языка программирования C. Если необходимо писать приложения, переносимые между базами данных, используйте высокоуровневый интерфейс MySQLdb, описанный в предыдущих разделах и избегайте прямого использования MySQLdb._mysql. Описание этого подмодуля намеренно слабая. Если вам это действительно нужно, то за дополнительной информацией обращайтесь к стандартной документации MySQL .

Содержание:

Пример работы с MySQLdb._mysql.

Итак, если все равно хотите использовать MySQLdb._mysql. Вот несколько примеров.

Самое простое подключение к базе данных:

from MySQLdb import _mysql
db=_mysql.connect()

Код выше создает соединение с сервером MySQL, работающим на локальной машине, используя стандартный сокет UNIX (или именованный канал в Windows), прочитает имя пользователя (из переменной среды USER), без пароля и не ИСПОЛЬЗУЕТ базу данных.

Передаем соединению больше информации:

db=_mysql.connect("localhost", "joebob", "moonpie", "thangs")

Код создает соединение с сервером MySQL, работающим на локальном компьютере, через сокет UNIX (или именованный канал), имя пользователя "joebob", пароль "moonpie" и выбирает исходную базу данных 'thangs'.

Аргументы, которые может принимать функция _mysql.connect() можно посмотреть в разделе "Создание подключения к базе данных MySQL". Хорошей практикой является передача аргументов, используя ключевые аргументы:

db=_mysql.connect(host="localhost", user="joebob",
                  passwd="moonpie", db="thangs")

Код делает то же самое, что и в предыдущем примере, но, возможно, его легче читать. Но так как хостом по умолчанию является 'localhost', и если имя пользователя базы данных 'joebob' совпадает с системным именем пользователя 'joebob', то можно сократить его до:

db=_mysql.connect(passwd="moonpie", db="thangs")

Сокеты UNIX и именованные каналы не работают по сети, следовательно, если указать хост, отличный от localhost, то будет использоваться TCP соединение, и если нужно, то еще можно указать порт подключения (порт по умолчанию 3306):

db=_mysql.connect(host="outhouse",port=3307,passwd="moonpie",db="thangs")

Можно подключиться к локальному хосту с помощью TCP, указав полное имя хоста или '127.0.0.1'.

Вообще, ставить пароли в свой код не такая уж хорошая идея:

db=_mysql.connect(host="outhouse", db="thangs", read_default_file="~/.my.cnf")

Код делает то же, что и предыдущий пример, но получает имя пользователя, пароль и другие параметры из конфигурационного файла /.my.cnf (UNIX-подобные системы). Подробнее читайте в официальном руководстве по использованию MySQL в разделе "4.2.2.2 Using Option Files".

Итак, теперь имеем открытое соединение с базой данных и нужно выполнить запрос. В MySQL нет курсоров и подстановки параметров, поэтому нужно передать полную строку запроса в db.query():

db.query("""SELECT spam, eggs, sausage FROM breakfast
         WHERE price < 5""")

Здесь нет возвращаемого значения, но могут быть вызваны исключения. Исключения определены в отдельном модуле MySQLdb._exceptions, но MySQLdb._mysql экспортирует их. Для перехвата исключений можно использовать класс _mysql.MySQLError.

На данный момент запрос был выполнен, и теперь нужно получить результаты. Для этого есть два варианта:

rows = db.store_result()
# ...или...
rows = db.use_result()

Оба метода возвращают объект результата. Какая разница? Метод db.store_result() немедленно возвращает весь набор результатов клиенту. Если набор результатов действительно велик, то это может быть проблемой. Один из способов обойти это - добавить в запрос SQL-команду LIMIT для ограничения количества возвращаемых строк. Другой способ - использовать метод db.use_result(), который хранит набор результатов на сервере и отправляет его построчно при выборке. Такое поведение связывает ресурсы сервера и связывает соединение. Другими словами - нельзя выполнять запросы, пока не получим все строки. Рекомендуется использовать db.store_result(), если только результирующий набор не слишком велик и при этом, по какой-либо причине невозможно использовать LIMIT.

Получение реальных результатов:

>>> rows.fetch_row()
# (('3','2','0'),)

Это может выглядеть немного странно. Первое, что нужно знать, это то, что метод .fetch_row() принимает некоторые дополнительные параметры. Первый аргумент maxrows - сколько строк должно быть возвращено. По умолчанию он возвращает одну строку. Он может вернуть меньше строк, чем передано аргументу (в случае если запрос вернул меньше maxrows), но не больше. Если установить maxrows=0, то он вернет все строки результирующего набора. Если при переборе результатов закончатся строки, то получите пустой кортеж.

Второй аргумент how - указывает, как должна быть представлена ​​строка. По умолчанию он равен нулю, что означает возврат в виде кортежа. Если how=1, то это означает, вернуть его как словарь, где ключами являются имена столбцов, или table.column, если есть два столбца с одинаковыми именами (скажем, из объединения). Если how=2, то это означает то же самое, что и how=1, за исключением того, что ключи всегда table.column (это для совместимости со старым модулем MySQLdb).

Итак, почему получили 1 кортеж с кортежем внутри? Потому что неявно запросили одну строку, так как не указали maxrows.

Другая странность: если предположить, что это числовые столбцы, то почему они возвращаются в виде строк? Потому что MySQL возвращает все данные в виде строк и ожидает, что пользователь сам их преобразует. Это было бы настоящей головной болью, но на самом деле MySQLdb._mysql может сделать это за вас. Чтобы выполнить автоматическое преобразование типов, нужно создать словарь преобразователя типов и передать его в функцию _mysql.connect() в качестве ключевого аргумента conv.

Ключи conv должны быть типами столбцов MySQL, которые в API для языка C имеют вид FIELD_TYPE_*. Можно получить эти значения следующим образом:

from MySQLdb.constants import FIELD_TYPE

По умолчанию любой тип столбца, который не может быть найден в conv, возвращается в виде строки, которая подходит для многих вещей.

Для разбираемого запроса необходимо следующее:

my_conv = { FIELD_TYPE.LONG: int }

Это означает, что если это FIELD_TYPE_LONG, то для него будет вызываться встроенная функция int(). Обратите внимание, что FIELD_TYPE_LONG - это столбец INTEGER, который соответствует длинному целому языка C, который также является типом, используемым для обычного целого числа Python. Будьте осторожны: если это действительно столбец UNSIGNED INTEGER, то это может привести к переполнению. По этой причине модуль MySQLdb для преобразования фактически использует long().

Затем, если использовать db=_mysql.connect(conv=my_conv...), то результаты вернутся как ((3, 2, 0)).

Сопоставление функций MySQL C API и MySQLdb._mysql.

Таблица соответствия MySQL C API функциям MySQLdb._mysql:

C API_mysql
mysql_affected_rows()conn.affected_rows()
mysql_autocommit()conn.autocommit()
mysql_character_set_name()conn.character_set_name()
mysql_close()conn.close()
mysql_commit()conn.commit()
mysql_connect()_mysql.connect()
mysql_data_seek()result.data_seek()
mysql_debug()_mysql.debug()
mysql_dump_debug_infoconn.dump_debug_info()
mysql_escape_string()_mysql.escape_string()
mysql_fetch_row()result.fetch_row()
mysql_get_character_set_info()conn.get_character_set_info()
mysql_get_client_info()_mysql.get_client_info()
mysql_get_host_info()conn.get_host_info()
mysql_get_proto_info()conn.get_proto_info()
mysql_get_server_info()conn.get_server_info()
mysql_info()conn.info()
mysql_insert_id()conn.insert_id()
mysql_num_fields()result.num_fields()
mysql_num_rows()result.num_rows()
mysql_options()_mysql.connect()
mysql_ping()conn.ping()
mysql_query()conn.query()
mysql_real_connect()_mysql.connect()
mysql_real_query()conn.query()
mysql_real_escape_string()conn.escape_string()
mysql_rollback()conn.rollback()
mysql_row_seek()result.row_seek()
mysql_row_tell()result.row_tell()
mysql_select_db()conn.select_db()
mysql_set_character_set()conn.set_character_set()
mysql_ssl_set()_mysql.connect()
mysql_stat()conn.stat()
mysql_store_result()conn.store_result()
mysql_thread_id()conn.thread_id()
mysql_use_result()conn.use_result()
mysql_warning_count()conn.warning_count()
CLIENT_*MySQLdb.constants.CLIENT.*
CR_*MySQLdb.constants.CR.*
ER_*MySQLdb.constants.ER.*
FIELD_TYPE_*MySQLdb.constants.FIELD_TYPE.*
FLAG_*MySQLdb.constants.FLAG.*