Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / MySQL / Интерфейсы для MySQL /
8  Perl
8  PHP
8  JavaScript
8  HTML
8  DHTML
8  XML
8  CSS
8  C / C++
8  Pascal и Delphi
8  Турбо Ассемблер
8  MySQL
8  CASE-технологии
8  Алгоритмы
8  Python
8  Обратная связь
8  Гостевая книга
Новости о мире


Интерфейс C для MySQL (окончание) - Программирование от RIN.RU
Интерфейс C для MySQL (окончание)



Основные вопросы и проблемы в использовании интерфейса C




Почему после успешных возвратов функции mysql_query() функция mysql_store_result() иногда возвращает NULL?


Для функции mysql_store_result() после успешного вызова функции mysql_query() возможен возврат величины NULL. Это может означать следующее:


  • Произошел сбой в выполнении функции mallow() (например, если результирующий набор данных слишком велик).

  • Данные не могли быть прочитаны (возникла ошибка в соединении).
    Запрос не вернул никаких данных (например, это был запрос вида INSERT, UPDATE или DELETE).


Проверить, вернула ли данная команда не пустой результирующий набор, всегда можно с помощью вызова функции mysql_field_count(). Если функция mysql_field_count() возвращает нуль, то данный результирующий набор является пустым и последний запрос представлял собой команду, которая не возвращает результирующие величины (например, INSERT или DELETE). Если функция mysql_field_count() возвращает величину, отличную от нуля, то данная команда должна была вернуть не пустой результат (см. описание функции mysql_field_count()).


Можно протестировать описанные ситуации на ошибку, вызывая функции mysql_error() или mysql_errno().


Какие результаты можно получить из запроса?


В дополнение к возвращенному запросом результирующему набору данных можно также получить следующую информацию:


  • Функция mysql_affected_rows() возвращает количество строк, подвергшихся воздействию во время последнего запроса при выполнении INSERT, UPDATE или DELETE. Исключение составляет случай использования команды DELETE без выражения WHERE, когда таблица воссоздается как пустая, а это намного быстрее! В таком случае функция mysql_affected_rows() в качестве количества подвергшихся воздействию записей возвращает нуль.

  • Функция mysql_num_rows() возвращает количество строк в результирующем наборе данных. Функция mysql_num_rows() может вызываться сразу же после возвращения функции mysql_store_result(). Совместно с функцией mysql_use_result() функция mysql_num_rows() может вызываться только после того, как извлечены все строки с помощью функции mysql_fetch_row().

  • Функция mysql_insert_id() возвращает идентификатор, созданный последним запросом, внесшим строку в таблицу с автоинкрементным полем (AUTO_INCREMENT, mysql_insert_id()).

  • Некоторые запросы (LOAD DATA INFILE ..., INSERT INTO ... SELECT ..., UPDATE) возвращают дополнительную информацию. Ее можно получить с помощью функции mysql_info(). Описание формата возвращаемой строки смотрите в описании функции mysql_info(). Если дополнительная информация отсутствует, то функция mysql_info() возвращает указатель NULL.




Как получить уникальный идентификатор для последней внесенной строки?


При внесении записи в таблицу, содержащую столбец с атрибутом AUTO_INCREMENT, последний сгенерированный идентификатор можно получить, вызвав функцию mysql_insert_id().


Для извлечения этого id можно также использовать функцию LAST_INSERT_ID() в строке запроса, передаваемой в mysql_query().


Для проверки, используется или нет поле AUTO_INCREMENT, можно выполнить следующий код. Этот код также проверяет, был ли данный запрос вида INSERT с использованием AUTO_INCREMENT:



if (mysql_error(&mysql)[0] == 0 &&
mysql_num_fields(result) == 0 &&
mysql_insert_id(&mysql) != 0)
{
used_id = mysql_insert_id(&mysql);
}


Самое последнее сгенерированное значение идентификатора сохраняется на сервере в течение времени жизни данного соединения. Это значение не может быть изменено другим клиентом, более того, оно не будет изменено даже при обновлении другого столбца AUTO_INCREMENT конкретной величиной (т.е. не NULL или 0).


Идентификатор, который был сгенерирован для одной таблицы, можно вставить в другую таблицу, используя команды SQL, как показано ниже:


INSERT INTO foo (auto,text)
VALUES(NULL,'text'); # генерация ID вставкой NULL
INSERT INTO foo2 (id,text)
VALUES(LAST_INSERT_ID(),'text'); # использование ID во второй таблице




Проблемы линкования с интерфейсом C


При линковании программы с клиентской библиотекой C в некоторых системах могут возникать следующие проблемы:



gcc -g -o client test.o -L/usr/local/lib/mysql -lmysqlclient -lsocket -lnsl


Undefined first referenced
symbol in file
floor /usr/local/lib/mysql/libmysqlclient.a(password.o)
ld: fatal: Symbol referencing errors. No output written to client




Если это случилось в вашей системе, то необходимо подключить математическую библиотеку путем добавления параметра -lm в конец строки компилирования/линкования.


Сборка клиентских программ


Клиенты MySQL, созданные собственноручно или полученные от сторонних фирм, при компилировании должны линковаться с использованием опций -lmysqlclient -lz в команде линкования. Возможно, потребуется задать опцию -L, чтобы указать компоновщику местоположение данной библиотеки. Например, если библиотека установлена в каталоге '/usr/local/mysql/lib', следует использовать в команде линкования выражение -L/usr/local/mysql/lib -lmysqlclient -lz.


Для клиентов, использующих файлы заголовков MySQL, при компиляции, возможно, потребуется задать опцию -I (например, -I/usr/local/mysql/include), чтобы компилятор мог найти требуемые файлы заголовков.


Как создать клиентскую программу с потоками


Клиентская библиотека почти безопасна при использовании в мультипоточном режиме. Наибольшая проблема заключается в том, что функции в 'net.c', читающие из сокетов, не поддерживают прерываний. Они были спроектированы исходя из предположения, что пользователь может захотеть иметь свой собственный аварийный сигнал, который способен прерывать слишком долгое чтение с сервера. При установке обработчиков прерываний для прерывания SIGPIPE управление сокетами должно быть поддерживающим потоки.


В более ранних бинарных поставках MySQL, которые мы (разработчики MySQL) распространяли с нашего веб-сайта (http://www.mysql.com/), клиентские библиотеки обычно не компилировались с возможностью поддержки потоков (бинарные поставки для Windows по умолчанию компилируются как поддерживающие потоки). Более новые бинарные поставки должны иметь как нормальную, так и поддерживающую потоки клиентскую библиотеку.


Чтобы получить поддерживающую потоки клиентскую программу с возможностью прерывать ее из других потоков и устанавливать блокировки по времени при соединении с сервером MySQL, необходимо использовать библиотеки -lmysys, -lmystrings и -ldbug libraries, а также код 'net_serv.o', используемый данным сервером.


Если нет необходимости в прерываниях или временных блокировках, то можно просто скомпилировать поддерживающую потоки клиентскую библиотеку (mysqlclient_r) и использовать ее (см. раздел Интерфейс C для MySQL). В этом случае нет необходимости заботиться об объектном файле net_serv.o или других библиотеках MySQL.


Если необходимо применять временные блокировки и прерывания при использовании поддерживающего потоки клиента, то можно с успехом использовать подпрограммы из файла 'thr_alarm.c'. При использовании подпрограмм из библиотеки mysys следует помнить только о том, что сначала следует вызвать функцию my_init()! См. раздел Описания функций C, связанных с потоками.


Все функции, за исключением mysql_real_connect(), по умолчанию являются поддерживающими потоки. Ниже приводятся рекомендации, как следует компилировать поддерживающую потоки клиентскую библиотеку и использовать ее в этом режиме (замечания по функции mysql_real_connect() справедливы также и для функции mysql_connect(), но поскольку функция mysql_connect() не рекомендуется, то в любом случае следует использовать функцию mysql_real_connect()).


Для того чтобы сделать функцию mysql_real_connect() поддерживающей потоки, необходимо перекомпилировать клиентскую библиотеку со следующей командой:



shell> ./configure --enable-thread-safe-client


Это создаст поддерживающую потоки клиентскую библиотеку libmysqlclient_r (предполагается, что данная операционная система включает поддерживающую потоки функцию gethostbyname_r()). Эта библиотека является поддерживающей потоки для данного соединения. Можно позволить двум потокам использовать одно и то же соединение со следующими оговорками:


  • Два потока не могут посылать запрос серверу MySQL в одно и то же время на одном и том же соединении. В особенности необходимо быть уверенным,
    что в промежутках между вызовом функций mysql_query() и mysql_store_result() никакой другой поток не использует это же
    соединение.

  • Многие потоки имеют доступ к различным результирующим наборам данных, извлекаемых функцией mysql_store_result().

  • При использовании функции mysql_use_result необходимо быть уверенным, что никакой другой поток не использует это же соединение, пока данный результирующий набор не будет обработан. Однако действительно наилучший вариант для потоковых клиентов, совместно использующих одно
    и то же соединение, - это применять функцию mysql_store_result().

  • Если необходимо использовать большое количество потоков на одном и том же соединении, то следует иметь синхронизирующую блокировку в отношении вызова комбинации функций mysql_query() и mysql_store_result(). Как только выполнение функции mysql_store_result() заканчивается, данная блокировка может сниматься и другие потоки могут запрашивать это же самое соединение.

  • Если вы программируете с использованием потоков POSIX, то можно использовать функции pthread_mutex_lock() и pthread_mutex_unlock() для установки и освобождения синхронизирующей блокировки.


Необходимо знать следующее: если имеется вызываемый функцией MySQL поток, который не создавал данное соединение с базой данных MySQL, то:
При вызове функций mysql_init() или mysql_connect() MySQL создаст специальные переменные для этого потока, которые (среди прочих применений) используются библиотекой отладки.


При вызове функции MySQL до того, как поток вызвал функции mysql_init() или mysql_connect(), данный поток в этом случае не будет иметь необходимых специальных переменных потока и, вероятно, программа рано или поздно умрет с дампом оперативной памяти.


Для более плавной работы программы необходимо выполнить следующие действия:


  1. Вызвать функцию my_init() при запуске данной программы, если она вызывает какую-либо другую функцию MySQL до вызова функции
    mysql_real_connect().

  2. Вызвать функцию mysql_thread_init() в обработчике потока до вызова иной функции MySQL.

  3. В данном потоке вызвать функцию mysql_thread_end() перед вызовом pthread_exit(). Это освободит память, занятую специальными переменными потока для MySQL.


Следует учитывать, что можно получить некоторые ошибки из-за наличия неопределенных символов при связывании клиента с библиотекой libmysqlclient_r. В большинстве случаев это происходит вследствие того, что в строку связывания/компилирования не включены библиотеки потока.


<<<  НазадВперед  >>>
 1  2  3  4  5  6 


 8  Комментарии к статье  8 8  Обсудить в чате

8  В тему

Интерфейс PHP API для MySQL

Интерфейс Perl API для MySQL

Поддержка ODBC в MySQL

Интерфейс C для MySQL

Интерфейсы C++ и не только

 
  
  
    Copyright ©  RIN 2003 - 2004      * Обратная связь