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

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

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

Начать курс

Введение: Зачем подключать базы данных к C++

Современные приложения на C++ редко обходятся без постоянного хранения данных. Будь то игровой сервер, система телеметрии или высоконагруженный backend — вам потребуется взаимодействие с СУБД. На рынке доминируют два принципиально разных подхода: реляционные (SQL) и документоориентированные (NoSQL) базы данных.

В этой статье мы разберём, как работать с PostgreSQL (через библиотеку libpqxx) и MongoDB (через официальный C++ драйвер mongo-cxx-driver). Вы узнаете, как настроить подключение, выполнять CRUD-операции и обрабатывать ошибки.

1. PostgreSQL и C++: реляционный подход

PostgreSQL — мощная объектно-реляционная СУБД с отличной поддержкой транзакций и сложных запросов. Для C++ рекомендуется использовать библиотеку libpqxx — современную, типобезопасную обёртку над libpq.

1.1 Установка libpqxx

Установка зависит от вашей ОС:

  • Ubuntu/Debian: sudo apt install libpqxx-dev
  • macOS (Homebrew): brew install libpqxx
  • Windows (vcpkg): vcpkg install libpqxx

1.2 Подключение и выполнение запросов

Рассмотрим минимальную программу для подключения к БД, создания таблицы и вставки данных:

#include <iostream>
#include <pqxx/pqxx>

int main() {
    try {
        // Подключение к базе данных
        pqxx::connection conn("dbname=testdb user=postgres password=secret hostaddr=127.0.0.1 port=5432");
        if (conn.is_open()) {
            std::cout << "Connected to PostgreSQL: " << conn.dbname() << std::endl;
        }

        // Создание транзакции
        pqxx::work txn(conn);

        // Создание таблицы
        txn.exec("CREATE TABLE IF NOT EXISTS users ("
                 "id SERIAL PRIMARY KEY,"
                 "name VARCHAR(100) NOT NULL,"
                 "email VARCHAR(255) UNIQUE NOT NULL"
                 ");");

        // Вставка данных (с параметризацией для безопасности)
        txn.exec_params("INSERT INTO users (name, email) VALUES ($1, $2);",
                        "Alice", "alice@example.com");

        // Подтверждение транзакции
        txn.commit();

        std::cout << "Data inserted successfully." << std::endl;

    } catch (const std::exception &e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

1.3 Чтение данных

Для выборки данных используйте итераторы по результату запроса:

pqxx::work txn(conn);
pqxx::result result = txn.exec("SELECT id, name, email FROM users;");

for (auto row : result) {
    int id = row["id"].as<int>();
    std::string name = row["name"].as<std::string>();
    std::string email = row["email"].as<std::string>();
    std::cout << id << ": " << name << " <" << email << ">" << std::endl;
}

2. MongoDB и C++: документоориентированный подход

MongoDB хранит данные в формате BSON (бинарный JSON). Для C++ используется официальный драйвер mongo-cxx-driver, построенный на основе библиотеки libmongoc.

2.1 Установка mongo-cxx-driver

  • Ubuntu: sudo apt install libmongoc-1.0-0 libbson-1.0-0 libmongocxx-dev
  • macOS: brew install mongo-cxx-driver
  • Сборка из исходников: Требуется cmake, libmongoc и libbson.

2.2 Подключение и CRUD-операции

Пример подключения к локальному инстансу MongoDB и вставки документа:

#include <iostream>
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>

int main() {
    // Инициализация драйвера (выполняется один раз)
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{"mongodb://localhost:27017"}};

    // Выбор базы данных и коллекции
    auto db = conn["testdb"];
    auto collection = db["users"];

    // Вставка документа (используем BSON builder)
    bsoncxx::builder::stream::document document{};
    document << "name" << "Bob"
             << "email" << "bob@example.com"
             << "age" << 30;

    auto result = collection.insert_one(document.view());
    if (result) {
        std::cout << "Inserted document with _id: "
                  << result->inserted_id().get_oid().value.to_string()
                  << std::endl;
    }

    // Поиск документа
    bsoncxx::builder::stream::document filter{};
    filter << "name" << "Bob";

    auto maybe_result = collection.find_one(filter.view());
    if (maybe_result) {
        std::cout << "Found: " << bsoncxx::to_json(maybe_result->view()) << std::endl;
    }

    return 0;
}

2.3 Обновление и удаление

Пример обновления возраста и удаления документа:

// Обновление: установить age = 31 для пользователя Bob
bsoncxx::builder::stream::document update_filter{};
update_filter << "name" << "Bob";

bsoncxx::builder::stream::document update_doc{};
update_doc << "$set" << bsoncxx::builder::stream::open_document
           << "age" << 31
           << bsoncxx::builder::stream::close_document;

collection.update_one(update_filter.view(), update_doc.view());                

Блоги

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