libpq++ [1] и libpqxx [2]. Обе библиотеки распространяются свободно, с открытым
исходным кодом и хорошо документированы.
Для себя я выбрал libpqxx: являясь очень гибкой, она остается так же достаточно простой в использовании.
Хотя, наверное, это и не самая простая библиотека, но однообразный интерфейс к данным
и привычные для C++ разработчика итераторы вместо "get_next_row" для доступа к результатам
запроса, делают ее использование интуитивно понятным. Так же поддерживаются потоки,
где это имеет смысл, а поля могут быть считаны в переменные шаблонными методами.
В общем, все, как в нормальных C++ библиотеках.
Вот несколько причин, по которым можно выбрать именно libpqxx:
- Согласованность с языком. В разумной мере используются фичи современного
C++ такие, как шаблоны (templates), исключения (exceptions), различного типы итераторов.
В библиотеке, по возможности, используются стандартные вещи из STL. - Структура, позволяющая писать "хороший" код. Многие проблемы обнаруживаются
на этапе компиляции или тестирования, а не во время работы. - Мощность. Такие встроенные фичи, как автоматическое восстановление соединения и
управление транзакциями освобождают разработчика от низкоуровневой рутинной работы. - Гибкость. С учетом описанного выше, можно сделать вывод, что это не фреймворк.
Ничто не заставляет втискивать свой код в чужие обработчики. В ней нет доморощенных
строк и классов исключений. Код библиотеки живет в своем пространстве имен (pqxx)
и полностью прячет нативный C API.
Итак, что же необходимо для работы?
Во-первых, необходима нативная libpq.so/libpq.dll.
Во-вторых, сама libpqxx.so/libpqxx.dll.
Что касается подхода к работе с базой данных, тут стоит обратить внимание, что
доступ к базе данных выполняются через объект транзакции pqxx::transaction.
Поэтому, знание интерфейсов этих классов является фундаментальным [3].
Для работы с libpqxx™ нам необходимо, как минимум следующие классы:
- pqxx::connection – представляет собой обвертку к соединению в программе к back-end'у PostgreSQL™.
Можно открывать множество соединений ко многим базам данных. - pqxx::work – тип для шаблона pqxx::transaction, представляющий собой саму транзакцию,
которая выполняется в контексте подключения (pqxx::connection). Если произойдет
какая-нибудь проблема в рамках этой транзакции – выполнится полный ее откат к исходному
состоянию. - pqxx::result – контейнер, содержащий результат работы запроса или команды выполненных
в транзакции.
на экран в виде field='value'.
#include <pqxx/connection>
#include <pqxx/transaction>
#include <iostream>
#include <string>
#include <sstream>
void help()
{
std::cout << "Usage: <host> <user> <password> <database>" << std::endl;
}
int main(int argc, char **argv)
{
// Check arguments
if (argc < 5) {
help();
return 1;
}
// Prepare connection string
std::ostringstream conn_string("");
conn_string << "host=" << argv[1]
<< " user=" << argv[2]
<< " password=" << argv[3]
<< " dbname=" << argv[4];
do {
// Create connection
try {
pqxx::connection conn(conn_string.str());
pqxx::work xact(conn, "SampleSelect");
std::string query("SELECT * from news limit 10");
// Execute query
try {
pqxx::result res = xact.exec(query);
if (!res.size()) {
std::cout << "Empty result set." << std::endl;
break;
}
// Show results
for (pqxx::result::const_iterator i = res.begin(), r_end = res.end(); i != r_end; ++i) {
// Iterate fields
for (pqxx::result::const_fielditerator f = i->begin(), f_end = i->end(); f != f_end; ++f) {
std::cout << f->name() << " = '" << f->c_str() << "'" << std::endl;
}
std::cout << std::endl;
}
} catch (...) {
std::cout << "Failed to execute query: " << query << std::endl;
break;
}
} catch (pqxx::broken_connection) {
std::cout << "Failed to establish connection." << std::endl;
break;
}
std::cout << "Query successfully executed." << std::endl;
return 0;
} while (false);
return 1;
}
Makefile выглядит следующим образом:
SRC=pqxx_sample.cpp
PROG=pqxx_sample
all:
c++ ${SRC} -o ${PROG} `pkg-config --libs --cflags libpqxx`
clean:
rm -f *.o ${PROG}
Как видно из примера, строкой подключения является стандартное перечисление ключ-значение,
которое можно собрать, например, в std::ostringstream [4].
Далее, подключение заворачивается в try-catch(pqxx::broken_connection).
После выполнения запроса выполняется двойной цикл: первый по записям, второй по полям.
Конструкция do {} while (false) здесь используется для уменьшения цикломатической сложности.
На этом возможности библиотеки libpqxx, естественно, не заканчиваются. О них можно
почитать в справочнике [3].
- libpq++ – http://www.postgresql.org/docs/7.2/static/libpqplusplus.html
- libpqxx – http://pqxx.org/development/libpqxx/
- Справочная информация – http://pqxx.org/devprojects/libpqxx/doc/3.0/html/Reference/
- std::ostringstream – http://www.cplusplus.com/reference/iostream/ostringstream/
5 комментариев:
DatabaseLayer как-то привычнее :)
Но да, wx-only.
Библиотека интересная, но вот документации - кот наплакал, тем более на русском языке.
Я только начал разбираться с этой библиотекой, и Doxygen - как-то не особо помогает, а идущий в комплекте "мануал" - слишком маленький, и "водянистый".
Интересут вот такой момент - параметризованные запросы в pqxx - как писать, и как с ними работать?
В догонку к предыдущему комментарию:
http://pqxx.org/devprojects/libpqxx/doc/3.0/html/Reference/a00020.html#9f9eaad80226ad78f8edd33d8a116e6a
using namespace pqxx;
void foo(connection_base &C)
{
C.prepare("findtable",
"select * from pg_tables where name=$1")
("varchar", treat_string);
work W(C);
result R = W.prepared("findtable")("mytable").exec();
if (R.empty()) throw runtime_error("mytable not found!");
}
Несколько необычно.
Для вставки можно использовать
void pqxx::tablewriter::insert(const TUPLE &)
Вот еще очень симпатичная либа
http://soci.sourceforge.net/
Отправить комментарий