MySQL & mSQL

Два API


Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

Таблица 13-1. С API для MySQL и mSQL



MySQL

mSQL

mysql_affected_rows()

CM. msqlQuery()

mysql_close()

msqlClose()

mysql_connect()

msqlConnect()

myql_create_db()


mysql_data_seek()

msqlDataSeek()

mysql_drop_db()


mysql_eof()


mysql_error()


mysql_fetch_field()

msqlFetchField()

mysql fetch lengths()


mysql_fetch_row()

msqlFetchRow()

mysql_field_count()


mysql_field_seek()

msqlFieldSeek()

mysql_free_result()

msqlFreeResult()

mysql_get_client_info()


mysql get host_info()


mysql_get_proto_info()


mysql_get_server_info()


mysql_init()


mysql_insert_id()


mysql_list_dbs( )

msqlListDBs()

mysql_list_fields()

msqlListFields()


msqlListIndex()

mysql_list_processes()


mysql_list_tables()

msqlListTables()

mysql_num_fields()

msqlNumFields()

mysql_num_rows()

msqlNumRows()

mysql_query()

msqlQuery()

<


mysql_real_query()







mysql_reload()







mysql_select_db()



msqlSelectDB()



mysql_shutdown()







mysql_stat()







mysql_store_result()



msqiStoreResult()



mysql_use_result()





API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include <sys/time. h>

    #include <stdio.h>

    #include <mysql.h>

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }



    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include <sys/time.h>

    #include <stdio.h>

    #include <msql.h>

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");



    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL



    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида «соединился, сделал запрос, закрылся». Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .




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