Работа с базами данных в C++: PostgreSQL и MongoDB на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Зачем 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 — если нужны

Блоги

Рекомендаций по книгам