Ответ
В C++ приложениях работа с БД происходит на нескольких уровнях:
- Уровень драйвера/низкоуровневого API: Прямые вызовы нативного API СУБД (например,
libpqдля PostgreSQL) или использование стандартизированных интерфейсов вроде ODBC. - Уровень обёртки/библиотеки: Использование библиотек, таких как SQLite C API, MySQL Connector/C++ или SOCI, которые предоставляют более удобный C++ интерфейс для выполнения запросов и управления соединениями.
- Уровень ORM/высокоуровневой абстракции (опционально): Применение ORM вроде ODB или sqlpp11 для отображения таблиц на C++ классы.
Пример работы на уровне библиотеки SQLite:
#include <sqlite3.h>
#include <iostream>
int main() {
sqlite3* db;
char* errMsg = nullptr;
// 1. Открытие соединения (уровень управления подключением)
if (sqlite3_open("test.db", &db) != SQLITE_OK) {
std::cerr << "Cannot open database: " << sqlite3_errmsg(db) << std::endl;
return 1;
}
// 2. Выполнение SQL-запроса (уровень запроса)
const char* sql = "SELECT id, name FROM users WHERE active = 1;";
sqlite3_stmt* stmt;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) == SQLITE_OK) {
// 3. Чтение результата (уровень обработки данных)
while (sqlite3_step(stmt) == SQLITE_ROW) {
int id = sqlite3_column_int(stmt, 0);
const unsigned char* name = sqlite3_column_text(stmt, 1);
std::cout << id << ": " << name << std::endl;
}
sqlite3_finalize(stmt);
}
sqlite3_close(db); // 4. Закрытие соединения
return 0;
}
На практике я проектирую слой доступа к данным, который инкапсулирует эту логику, разделяя ответственность между выполнением сырых SQL-запросов, маппингом результатов в объекты предметной области и управлением транзакциями.