SQLite для C++: полное руководство с примерами

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

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

Начать курс

Что такое SQLite и зачем он нужен в C++?

SQLite — это легковесная, встраиваемая реляционная база данных, которая не требует отдельного серверного процесса. В отличие от MySQL или PostgreSQL, SQLite работает непосредственно с файлом базы данных на диске, что делает её идеальным выбором для настольных приложений, мобильных устройств, встраиваемых систем и небольших веб-проектов.

Для языка C++ существует несколько способов работы с SQLite. Самый популярный и стабильный — это использование официальной библиотеки sqlite3 (C API), которая поставляется в виде набора C-функций. Однако для более удобной работы в C++ часто используют обёртки, такие как SQLiteCpp или sqlite_modern_cpp. В этой статье мы сосредоточимся на прямом использовании C API (библиотека sqlite3), так как это даёт максимальный контроль и понимание происходящих процессов.

Основные преимущества SQLite:

  • Нулевая конфигурация: не нужно устанавливать и настраивать сервер.
  • Портативность: база данных — это один файл.
  • Надёжность: поддержка транзакций (ACID).
  • Скорость: для большинства операций работает быстрее клиент-серверных БД.
  • Размер: библиотека занимает менее 600 КБ.

Установка SQLite для C++

Установка зависит от вашей операционной системы и компилятора. Мы рассмотрим три основных способа.

1. Установка через пакетный менеджер (Linux/macOS)

Ubuntu/Debian:

sudo apt-get update
sudo apt-get install libsqlite3-dev

macOS (Homebrew):

brew install sqlite3

Fedora:

sudo dnf install sqlite-devel

2. Установка на Windows (vcpkg)

Если вы используете vcpkg:

vcpkg install sqlite3:x64-windows
vcpkg integrate install

После этого в Visual Studio можно подключать #include <sqlite3.h>.

3. Компиляция из исходников (универсальный способ)

Скачайте файлы sqlite3.c и sqlite3.h с официального сайта sqlite.org. Затем просто добавьте их в ваш проект:

g++ main.cpp sqlite3.c -o myapp -lpthread -ldl

На Windows может потребоваться дополнительно указать -lws2_32.

Быстрый старт: первая программа с SQLite на C++

Создадим простое консольное приложение, которое открывает базу данных, создаёт таблицу и вставляет одну запись.

#include <iostream>
#include <sqlite3.h>

int main() {
    sqlite3 *db;
    char *errMsg = 0;

    // 1. Открываем (или создаём) базу данных
    int rc = sqlite3_open("test.db", &db);
    if (rc) {
        std::cerr << "Ошибка открытия БД: " << sqlite3_errmsg(db) << std::endl;
        return 1;
    }

    // 2. Создаём таблицу
    const char *sqlCreate = "CREATE TABLE IF NOT EXISTS users ("
                            "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                            "name TEXT NOT NULL, "
                            "age INTEGER);";

    rc = sqlite3_exec(db, sqlCreate, 0, 0, &errMsg);
    if (rc != SQLITE_OK) {
        std::cerr << "Ошибка SQL: " << errMsg << std::endl;
        sqlite3_free(errMsg);
        sqlite3_close(db);
        return 1;
    }

    // 3. Вставляем данные
    const char *sqlInsert = "INSERT INTO users (name, age) VALUES ('Alice', 30);";
    rc = sqlite3_exec(db, sqlInsert, 0, 0, &errMsg);
    if (rc != SQLITE_OK) {
        std::cerr << "Ошибка вставки: " << errMsg << std::endl;
        sqlite3_free(errMsg);
    } else {
        std::cout << "Запись добавлена, ID: " << sqlite3_last_insert_rowid(db) << std::endl;
    }

    // 4. Закрываем базу
    sqlite3_close(db);
    return 0;
}

Скомпилируйте и запустите. В текущей папке появится файл test.db.

Основные методы и функции SQLite C API

Рассмотрим 10 ключевых функций, которые покроют 90% ваших задач.

1. sqlite3_open()

Что делает: Открывает соединение с файлом базы данных. Если файл не существует, создаёт его.

Параметры:

  • const char *filename — путь к файлу БД (или ":memory:" для in-memory БД).
  • sqlite3 **ppDb — указатель на указатель на объект соединения.

Возвращает: SQLITE_OK (0) при успехе, иначе код ошибки.

Пример:

sqlite3 *db;
int rc = sqlite3_open("mydb.sqlite", &db);
if (rc != SQLITE_OK) {
    // Обработка ошибки
}

2. sqlite3_close()

Что делает: Закрывает соединение с БД и освобождает ресурсы.

Параметры:

  • sqlite3 *db — указатель на соединение.

Пример:

sqlite3_close(db);

3. sqlite3_exec()

Что делает: Выполняет один или несколько SQL-запросов, разделённых точкой с запятой. Удобен для DDL (CREATE, DROP) и простых DML.

Параметры:

  • sqlite3 *db — соединение.
  • const char *sql — SQL-запрос(ы).
  • int (*callback)(void*,int,char**,char**) — функция обратного вызова для обработки результатов (можно NULL).
  • void *arg — пользовательские данные для callback.
  • char **errmsg — указатель на строку с сообщением об ошибке.

Пример:

char *errMsg = 0;
const char *sql = "CREATE TABLE IF NOT EXISTS test (id INT);";
int rc = sqlite3_exec(db, sql, 0, 0, &errMsg);
if (rc != SQLITE_OK) {
    std::cerr << errMsg;
    sqlite3_free(errMsg);
}

4. sqlite3_prepare_v2()

Что делает: Компилирует SQL-запрос в подготовленный стейтмент. Это основной способ выполнения запросов с параметрами.

Параметры:

  • sqlite3 *db — соединение.
  • const char *zSql — SQL-запрос.
  • int nByte — длина строки (или -1, если строка нуль-терминирована).
  • sqlite3_stmt **ppStmt — указатель на стейтмент.
  • const char **pzTail — указатель на остаток строки (можно NULL).

Пример:

sqlite3_stmt *stmt;
const char *sql = "SELECT * FROM users WHERE age > ?";
sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
sqlite3_bind_int(stmt, 1, 25); // Подставляем значение

5. sqlite3_bind_*() (bind_int, bind_text, bind_double, bind_null)

Что делает: Привязывает значения к параметрам (плейсхолдерам) в подготовленном запросе. Параметры обозначаются знаком ? или ?NNN или :AAA.

Параметры:

  • sqlite3_stmt *stmt — стейтмент.
  • int index — индекс параметра (начиная с 1).
  • value — значение соответствующего типа.

Пример:

sqlite3_bind_int(stmt, 1, 42);
sqlite3_bind_text(stmt, 2, "John", -1, SQLITE_TRANSIENT);
sqlite3_bind_double(stmt, 3, 3.14);
sqlite3_bind_null(stmt, 4);

6. sqlite3_step()

Что делает: Выполняет один шаг стейтмента. Для SELECT возвращает строку результата (SQLITE_ROW), для INSERT/UPDATE/DELETE — SQLITE_DONE.

Параметры:

  • sqlite3_stmt *stmt — стейтмент.

Пример:

while (sqlite3_step(stmt) == SQLITE_ROW) {
    int id = sqlite3_column_int(stmt, 0);
    const char *name = sqlite3_column_text(stmt, 1);
    std::cout << id << " " << name << std::endl;
}

7. sqlite3_column_*() (column_int, column_text, column_double, column_bytes)

Что делает: Извлекает значение из текущей строки результата по индексу колонки (начиная с 0).

Параметры:

  • sqlite3_stmt *stmt — стейтмент.
  • int iCol — индекс колонки.

Пример:

int age = sqlite3_column_int(stmt, 2);
const unsigned char *name = sqlite3_column_text(stmt, 1);
int nameLen = sqlite3_column_bytes(stmt, 1);

8. sqlite3_finalize()

Что делает: Уничтожает подготовленный стейтмент и освобождает память. Обязателен после завершения работы со стейтментом.

Параметры:

  • sqlite3_stmt *stmt — стейтмент.

Пример:

sqlite3_finalize(stmt);

9. sqlite3_errmsg()

Что делает: Возвращает текст последней ошибки для данного соединения.

Параметры:

  • sqlite3 *db — соединение.

Пример:

if (rc != SQLITE_OK) {
    std::cerr << "Ошибка: " << sqlite3_errmsg(db) << std::endl;
}

10. sqlite3_last_insert_rowid()

Что делает: Возвращает ID последней вставленной строки в текущем соединении (для таблиц с AUTOINCREMENT).

Параметры:

  • sqlite3 *db — соединение.

Пример:

sqlite3_exec                    

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