MySQL- Руководство разработчика

Примечания относительно хранения на сервере


MySQL предлагает два немного различных пути доступа к данным из базы данных.

Заданный по умолчанию метод в MySQLmodule состоит в том, чтобы использовать хранение на стороне пользователя, то есть все запросы, включая методы курсора (STH), выбирают все данные с сервера. К строкам обращаются через STH.fetchrows(n) или STH.fetchdict(n) индивидуально (n=1), блочно (n>1), все строки забирают одной порцией (n<0) или не обращаются вообще (n=0). STH.numrows() может сообщать после запроса сколько строк находится в результате. STH.seek(k) может использоваться, чтобы обратиться к строкам в произвольном порядке. Недостаток хранения на стороне пользователя состоит в том, что это использует память пользователя, чтобы сохранить все строки. Этот способ учитывает конструкции типа: STH = DBH.query("select * from Foo") N = STH.numrows() if N > 1000: raise Hell,"You must be joking!" for i in xrange(N): [Data] = STH.fetchdict(1)

Так как пользователь действительно переместил к себе все строки, которые подготовил сервер, все транзакции на этом канале прекратились, и сервер готов принять новые команды. Это также означает, что STH.eof() всегда true (1) для хранения данных на стороне клиента.

Хранение на стороне сервера не требует, чтобы у пользователя было много памяти. Все записи будут перемещены на основании запроса. Однако, этот способ имеет несколько недостатков. Так как теперь возникает возможность того, что пользователь не забрал все строки, каждая новая команда должна проверить, является ли свободным, то есть готов ли он принять новую команду. Если нет, команда должна очистить канал команды, выдавая запросы на чтение в количестве, достаточном, чтобы получить оставшиеся строки. MySQL API 3.21 не предлагает команды abort(). STH.numrows() не знает ничего относительно того, сколько строк были выбраны запросом, так что вышеупомянутый код примера будет падать. STH.numrows() будет, однако, модифицироваться, поскольку строки все-таки читаются, например: STH = DBH.query("select * from Foo") Data = STH.fetchrows(-1) print "Got",STH.numrows(),"rows." # len(Data) is the same


STH.eof() имеет смысл только при хранении данных на сервере, но даже здесь такой код полезен не всегда: STH = DBH.query("select 1") print STH.eof() # will print 0 Data = STH.fetchrows(1) # retrieve the row print STH.eof() # still 0 :-( Data = STH.fetchrows(1) # must repeat. Data will be [] print STH.eof() # now we get 1, but we already # knew that we've hit the end
Можно было рассматривать это, как ошибку. STH.seek(k) больше не доступен и создает исключение ("cannot seek on server"), то есть строки должны теперь читаться последовательно.
Хранение на стороне сервера также создает дополнительную нагрузку на сервер. В частности, он должен остаться в контакте с пользователем, пока все строки не будут прочитаны. Так что лучше бы быстро получить все строки и не делать длинную обработку или, что еще хуже, позволять пользователю останавливать поиск (например, нажимая клавиши Ctrl-S в интерактивном интерфейсе).
Для тех, кто не может решить, который метод является более подходящим для прикладной программы, MySQLmodule позволяет смешивать оба метода свободно. Заданное по умолчанию поведение может быть установлено через DBH.selectdb() и может быть изменено для индивидуального курсора (STH). Обратите внимание, что незавершенные запросы будут отменены последующими командами: STH = DBH.query("select * from Foo",1) # use server side storage Tables = DBH.listtables() # stomp on previous results Data = STH.fetchrows() # nothing here anymore vs. STH = DBH.query("select * from Foo",0) # use client side storage Tables = DBH.listtables() # won't interfere Data = STH.fetchrows() # no problem...
Хранение на стороне сервера также создает более сложный код в MySQLmodule. Обычно при хранении на стороне клиента STH-курсоры независимы от дескриптора базы данных. Немедленно после запроса все данные будут перекачаны клиенту, и пользователь может делать все, что сочтет необходимым с дескриптором DBH. Но при хранении на стороне сервера это становится сложным. С курсорами стороны сервера указатель на дескриптор сохранен в дескрипторе STH. MySQLmodule удостоверится, что этот кусок памяти не освобожден прежде, чем закроются все ожидающие обработки курсоры. Это означает, что mysql_close() не обязательно вызван, если база данных, обрабатываемая DBH, разрушена: DBH = MySQL.connect() # get a DB handle STH = DBH.query("select 1",1) # server side cursor del DBH # mysql_close() *not* called STH.fetchrows() # will succeed! del STH # now mysql_close() will be called # in DBH_dealloc()
Если Вы должны закрыть дескриптор DB немедленно, используйте DBH.close(). Все дальнейшие попытки работать на этом дескрипторе (даже ожидающие обработки курсоры стороны сервера) получат исключительную ситуацию "... server has gone away". Начиная с того момента, как mySQL не может принимать команды из последовательности, все DBH-методы должны проверить незавершенные STH-курсоры. Чтобы обращаться к ним, дескриптор DBH хранит указатель на STH-курсор.

Содержание раздела