MySQL++

MySQL++ — это специализированная библиотека так называемых «обёрточных» (wrapper) методов для прикладного программного интерфейса C API для СУБД MySQL. Главная цель этой библиотеки — сделать работу с SQL-запросами такой же простой, как работа с STL-контейнерами.

Самую последнюю версию библиотеки MySQL++ можно найти на официальном Web-сайте. Тем не менее, чтобы избежать дополнительных сложностей, лучше обратиться к репозиторию пакетов для вашего дистрибутива.

2. Краткое описание основных объектов (соединение, запрос, результаты)

MySQL++ обеспечивает поддержку большинства разнообразных способов и приёмов работы с базами данных. И всё же, несмотря на это разнообразие, можно выделить обобщённую схему использования API-интерфейса, предназначенного для доступа к базам данных:

  • создание (открытие) соединения с базой данных,
  • формирование и выполнение запроса,
  • при успешном выполнении запроса — обработка итогового набора (result set) — итеративный последовательный проход по записям этого набора,
  • если выполнение запроса завершилось неудачно, то необходимо обеспечить обработку ошибок (исключений).

Каждому из перечисленных выше этапов соответствует класс или иерархия классов библиотеки MySQL++. Рассмотрим их немного подробнее.

2.1. Объект Connection (соединение)

Объект Connection управляет соединением с сервером MySQL. Для того чтобы выполнять какие-либо операции в базе данных, необходим по меньшей мере один такой объект. В приложении использование всех прочих MySQL++-объектов зависит (хотя и не всегда непосредственно) от экземпляра Connection, поэтому пока в вашей программе применяются объекты библиотеки MySQL++, должен существовать и объект Connection.

В СУБД MySQL допускается использование нескольких различных типов соединений между клиентом и сервером: сокеты TCP/IP, сокеты Unix-домена, именованные программные каналы. Базовый класс Connection поддерживает все эти типы соединений. Какой именно тип соединения необходим в каждом конкретном случае, вы определяете с помощью параметров, передаваемых в метод Connection::connect(). Но если вы заранее решили, что ваше приложение будет работать только с одним типом соединений, то вашему вниманию предлагаются специализированные подклассы с упрощёнными интерфейсами. Например, если в программе предполагаются обращения исключительно к сетевому серверу баз данных, то вы можете воспользоваться подклассом TCPConnection.

2.2. Объект Query (запрос)

Чаще всего SQL-запросы создаются с использованием объекта Query, инициализируемого объектом Connection.

Query работает практически аналогично потоку вывода в стандартном C++, поэтому вы можете записывать в него данные так же, как в std::cout или std::ostringstream. Это наиболее близкий стилю языка C++ способ, используемый MySQL++ для компоновки строк запросов. В библиотеку включены манипуляторы потока с контролем типов данных, что существенно упрощает создание синтаксически корректных SQL-команд.

Ещё одной функциональной особенностью Query являются запросы-шаблоны (Template Queries), которые в определённой степени напоминают функцию языка C printf: формируется строка запроса с включаемыми в неё тэгами, обозначающими места вставки переменных элементов данных. Это удобно в тех случаях, когда в программе используются многочисленные запросы с одинаковой структурой — определив один шаблон, вы можете применять его многократно в различных частях своего приложения.

Третий метод создания запросов — использование объекта Query совместно со специализированными структурами SSQLS (Specialized SQL Structures), которые позволяют создавать структуры C++, являющиеся точным отображением схем конкретных баз данных. Это даёт объекту Query информацию, необходимую для формирования обобщённых SQL-запросов.

2.3. Наборы результатов (Result Sets)

Данные полей в наборе результатов запроса сохраняются в специальном классе с именем String (аналог стандартного std::string). Этот класс предоставляет операторы для автоматизированного преобразования объектов наборов результатов в любой базовый тип C/C++. Кроме того, MySQL++ определяет классы, такие как DateTime, которые вы можете инициализировать данными SQL-типа DATETIME. Для этих автоматических преобразований осуществляется контроль их корректности, и при ошибках конвертации выставляется соответствующий флаг-предупреждение или генерируется исключение (в зависимости от настроек библиотеки).

Для предоставления результатов выполнения SQL-команд в библиотеке MySQL++ реализованы следующие подходы.

2.3.1. Команды, не возвращающие данные

Не все команды SQL возвращают данные. Пример такой команды CREATE TABLE. Для подобных команд имеется специальный тип результата (SimpleResult), который возвращает только состояние после выполнения команды: успешное завершение выполнения команды, количество строк, на которые подействовала команда (если подразумевалось какое-либо воздействие), и т.п.

2.3.2. Запросы, возвращающие данные: структуры данных MySQL++

Самый простой способ получения набора результатов — использование метода Query::store(). Этот метод возвращает объект StoreQueryResult, являющийся производным от std::vector<mysqlpp::Row>, представляющий собой контейнер с произвольным доступом, сформированный из Row-строк. В свою очередь, каждый объект Row является аналогом вектора (std::vector) строк (тип String), по одному объекту на каждое поле в наборе результатов. Таким образом, вы можете рассматривать StoreQueryResult как двумерный массив, т.е. чтобы получить пятое поле из второй строки, можно просто написать result[1][4]. К полям можно обращаться и по их именам, поэтому возможна и такая форма записи: result[1][«price»].

Несколько менее удобным способом работы с набором результатов является применение метода Query::use(), возвращающего объект UseQueryResult. Этот класс функционирует подобно стандартному STL-итератору. В этом случае произвольного доступа к данным уже не получится — вы последовательно проходите по строкам набора результатов с ограничением по направлению: только от начала к концу. Нет возможности возвращаться к уже пройденным строкам, и вы не знаете, сколько строк в данном наборе до тех пор, пока не достигнете последней строки. В качестве компенсации за эти неудобства вы получаете более рациональное использование оперативной памяти, поскольку нет необходимости загружать в память весь набор полностью. Это особенно важно, если приходится работать с чрезвычайно большими наборами результатов.

2.3.3. Запросы, возвращающие данные: специализированные структуры SSQLS

Доступ к результатам запросов посредством структур данных библиотеки MySQL++ представляет достаточно низкий уровень абстракции — это лучше, чем применение MySQL C API-интерфейса, но не намного. Приблизить логику решения к предметной области задачи можно с помощью специализированных структур SSQLS (Specialized SQL Structures). Эти SSQLS-объекты позволяют определять структуры языка C++, которые соответствуют структурам таблиц в схеме конкретной базы данных. Кроме того, гораздо проще состыковать SSQLS-объекты со стандартными STL-контейнерами (а следовательно, и с алгоритмами).

Преимущество этого способа заключается в том, что в программе потребуется включение минимального объёма SQL-кода. Можно выполнить запрос и получить результат в виде структур данных языка С++, доступ к которым не отличается от доступа к любым другим структурам. Доступ к полученным данным можно организовать через объект Row или же обратиться к методам библиотеки, чтобы «сбросить» результаты в STL-контейнер — с последовательным, произвольным или ассоциативным доступом — выбор за вами.

Рассмотрим следующий фрагмент кода:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <iomanip>
#include <mysql++.h>
 
using namespace std;
 
int main( int argc, char *argv[] )
{
  // установление соединения с тестовой базой данных
  mysqlpp::Connection con( false );
  if( con.connect( "test_db", "localhost", "tdb_user", "tdb_password" ) )
  {
    // выполнение запроса и вывод полученных результатов
    mysqlpp::Query query = con.query( "select name from dvd" );
    if( mysqlpp::StoreQueryResult res = query.store() )
    {
      cout << "Коллекция DVD: " << endl;
      for( size_t i = 0; i < res.num_rows(); i++ )
        cout << res[i][0] << endl;
    }
    else
    {
      cerr << "Ошибка при получении списка DVD: " << query.error() << endl;
      return -1;
    }
    return 0;
  }
  else
  {
    cerr << "Ошибка при установлении соединения с БД: " << con.error << endl;
    return -1;
  }
}
1
2
3
4
5
vector<stock> result;
query << "SELECT * FROM stock";
query.storein( result );
for( vector<stock>::iterator i = result.begin(); i != result.end(); i++ )
  cout << "Цена: " << i->price << endl;

Практически «чистый» код на C++, без излишеств.

Если по каким-либо причинам создание SSQLS-объектов, соответствующих структурам таблиц баз данных, нежелательно или невозможно, то вы можете использовать объект Row, и приведённый выше фрагмент кода теперь будет выглядеть так:

1
2
3
4
5
vector<mysqlpp::Row> result;
query << "SELECT * FROM stock";
query.storein( result );
for( vector<mysqlpp::Row>::iterator i = result.begin(); i != result.end(); i++ )
  cout << "Цена: " << i->at("price") << endl;

Различия невелики. Первый фрагмент выглядит более лаконично, но на внутреннюю логику это не влияет.

2.4. Ошибки и исключения

По умолчанию при возникновении ошибок библиотека генерирует исключения (exceptions). При необходимости вы можете настроить вместо генерации исключений установку специального флага ошибки (error flag), но помните, что исключения предоставляют более подробную информацию. В пределах одного блока try-catch вы можете выявлять различные типы ошибок.


В начало

3. Простой пример использования MySQL++

В следующем примере показано создание (открытие) соединения с базой данных, выполнение простого запроса и вывод полученных результатов — всё, о чём мы говорили до сих пор.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <iomanip>
#include <mysql++.h>
 
using namespace std;
 
int main( int argc, char *argv[] )
{
  // установление соединения с тестовой базой данных
  mysqlpp::Connection con( false );
  if( con.connect( "test_db", "localhost", "tdb_user", "tdb_password" ) )
  {
    // выполнение запроса и вывод полученных результатов
    mysqlpp::Query query = con.query( "select name from dvd" );
    if( mysqlpp::StoreQueryResult res = query.store() )
    {
      cout << "Коллекция DVD: " << endl;
      for( size_t i = 0; i < res.num_rows(); i++ )
        cout << res[i][0] << endl;
    }
    else
    {
      cerr << "Ошибка при получении списка DVD: " << query.error() << endl;
      return -1;
    }
    return 0;
  }
  else
  {
    cerr << "Ошибка при установлении соединения с БД: " << con.error << endl;
    return -1;
  }
}

Для обеспечения работы примера необходимо создать базу данных MySQL с именем test_db, содержащую таблицу с именем dvd. Эта таблица может иметь, например, следующую структуру:

name   VARCHAR(50)
genre  TEXT(70)
price  REAL
bought DATE

После того как тестовая база данных test_db создана, администратор MySQL должен создать пользователя с правами работы в ней. Имя и пароль для этого пользователя уже были указаны в приведённом выше исходном коде примера.

CREATE USER [email protected] IDENTIFIEDBY 'tdb_password';
GRANT ALL PRIVILEGES ON test_db.* TO [email protected];

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

Что касается самой программы, то она запрашивает только поле имён (name) из таблицы dvd, и из полученного набора результатов res последовательно выводит все строки (названия DVD). Пример очень простой, но в нём проиллюстрированы три из четырёх этапов, упомянутых в начале данной статьи. О четвёртом этапе — обработке исключений — речь пойдёт в одной из следующих статей цикла.


http://blog.wel.org.ua

работаю админом, прогером сеошнегом :)

Leave a Comment

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Загрузка...
Menu Title