Введение: Зачем C++ разработчику базы данных?
C++ — один из самых мощных языков системного программирования. Однако даже в высоконагруженных проектах редко удаётся обойтись без сохранения данных. Будь то игровой сервер, финансовое приложение или система IoT — вам понадобится надёжное хранилище. В этой статье мы разберём два популярных подхода: реляционную СУБД PostgreSQL и документоориентированную MongoDB. Вы узнаете, как подключить их к проекту на C++, выполнить базовые операции и избежать типичных ошибок.
1. PostgreSQL в C++: классика реляционных БД
PostgreSQL — зрелая, надёжная СУБД с отличной поддержкой транзакций и сложных запросов. Для работы с ней из C++ чаще всего используют библиотеку libpqxx — официальный C++-враппер над libpq.
Установка и подключение
Установите libpqxx через пакетный менеджер или соберите из исходников:
# Ubuntu/Debian
sudo apt-get install libpqxx-dev
# macOS (Homebrew)
brew install libpqxx
В CMakeLists.txt добавьте:
find_package(PQXX REQUIRED)
target_link_libraries(your_project pqxx::pqxx)
Подключение к базе и простой SELECT
Рассмотрим минимальный пример — получение списка пользователей:
#include <iostream>
#include <pqxx/pqxx>
int main() {
try {
// Строка подключения: "host=... dbname=... user=... password=..."
pqxx::connection conn("host=localhost dbname=testdb user=admin password=secret");
pqxx::work txn(conn);
// Выполняем запрос
pqxx::result result = txn.exec("SELECT id, name, email FROM users LIMIT 10");
for (auto row : result) {
std::cout << "ID: " << row[0].as<int>()
<< ", Name: " << row[1].as<std::string>()
<< ", Email: " << row[2].as<std::string>() << std::endl;
}
txn.commit(); // Завершаем транзакцию
} catch (const std::exception &e) {
std::cerr << "Ошибка: " << e.what() << std::endl;
return 1;
}
return 0;
}
Обратите внимание: все операции обёрнуты в блок try-catch — libpqxx генерирует исключения при любых сбоях.
Параметризованные запросы (безопасность)
Никогда не конкатенируйте строки для подстановки значений — это открывает путь для SQL-инъекций. Используйте подготовленные выражения:
pqxx::work txn(conn);
// Подготовка
conn.prepare("insert_user", "INSERT INTO users (name, email) VALUES ($1, $2)");
// Выполнение с параметрами
txn.exec_prepared("insert_user", "Иван Петров", "ivan@example.com");
txn.commit();
2. MongoDB в C++: гибкость NoSQL
MongoDB хранит данные в формате BSON (бинарный JSON) и отлично подходит для задач, где схема данных может меняться. Официальный драйвер для C++ — mongocxx (поверх mongoc).
Установка драйвера mongocxx
Сборка из исходников — самый надёжный способ. Краткая инструкция:
# Установите зависимости: libmongoc, libbson, cmake
git clone https://github.com/mongodb/mongo-cxx-driver.git
cd mongo-cxx-driver/build
cmake .. -DCMAKE_BUILD_TYPE=Release -DBSONCXX_POLY_USE_MNMLSTC=ON
make -j4
sudo make install
В CMakeLists.txt:
find_package(libmongocxx REQUIRED)
target_link_libraries(your_project mongocxx::mongocxx)
Подключение и вставка документа
#include <iostream>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>
int main() {
// Инициализация драйвера (один раз на приложение)
mongocxx::instance inst{};
// Подключение к локальному экземпляру MongoDB
mongocxx::client conn{mongocxx::uri{"mongodb://localhost:27017"}};
auto db = conn["testdb"];
auto collection = db["users"];
// Создаём BSON-документ
bsoncxx::builder::stream::document document{};
document << "name" << "Анна"
<< "email" << "anna@example.com"
<< "age" << 28
<< "tags" << bsoncxx::builder::stream::open_array
<< "cpp" << "mongodb"
<< bsoncxx::builder::stream::close_array;
// Вставка
auto result = collection.insert_one(document.view());
if (result) {
std::cout << "Вставлен документ с ID: "
<< result->inserted_id().get_oid().value.to_string() << std::endl;
}
return 0;
}
Запросы с фильтрацией
// Поиск пользователей старше 25 лет
auto filter = bsoncxx::builder::stream::document{} << "age" <<
bsoncxx::builder::stream::open_document << "$gt" << 25 << close_document << finalize;
auto cursor = collection.find(filter.view());
for (auto doc : cursor) {
std::cout << bsoncxx::to_json(doc) << std::endl;
}
Обратите внимание: mongocxx использует свой собственный тип исключений (mongocxx::exception), поэтому оборачивайте код в try-catch аналогично примеру с PostgreSQL.
3. Сравнение и практические рекомендации
Какую базу выбрать? Ответ зависит от задачи:
- PostgreSQL — если нужны