C++链接并操作嵌入式数据库SQLite

1. 简单介绍

SQLite是一个以C语言库形式发布的嵌入式数据库引擎。在C++项目中使用它,主要有两种方式:

  • 直接使用C API :这是最直接、最底层的方式。SQLite本身提供一个纯C语言编写的头文件(sqlite3.h)和库文件(如 sqlite3.lib, sqlite3.dlllibsqlite3.a, libsqlite3.so)。

    • 步骤

      1. 获取库文件:从SQLite官网下载预编译的二进制文件,或下载源码自行编译。

      2. 配置项目

        • 在项目中包含 sqlite3.h头文件。

        • 在链接器设置中,添加SQLite的库文件路径,并链接 sqlite3库。

      3. 代码中调用 :在C++代码中,可以直接调用SQLite的C API函数,如 sqlite3_open(), sqlite3_exec(), sqlite3_prepare_v2()等。由于C++兼容C,这种方式是原生支持的。

  • 使用C++封装库 :为了获得更符合C++编程习惯(如RAII、异常安全、面向对象)的接口,社区创建了许多C++封装库。一个流行且轻量级的选择是 SQLiteCpp。它包装了原始C API,提供了更现代、更安全的C++接口。

    • 步骤

      1. 获取库:通过包管理器(如vcpkg, conan)安装,或从GitHub获取源码。

      2. 包含头文件 :包含 SQLiteCpp.h

      3. 使用C++风格接口 :使用 SQLite::Database, SQLite::Statement等类进行操作,代码更简洁,资源管理更安全。

2. 基本操作流程

C++ 操作 SQLite 通常需要以下步骤:

1. 链接 SQLite 库

静态链接

复制代码
// 直接包含 sqlite3.c 源文件到项目中
#include "sqlite3.c"

// 编译时:g++ main.cpp -o app -lpthread -ldl

动态链接

cpp 复制代码
// 使用头文件和动态库
#include <sqlite3.h>

// 编译时:g++ main.cpp -o app -lsqlite3 -lpthread -ldl

各参数说明:

  • g++:C++ 编译器

  • main.cpp:你的源代码文件

  • -o app:指定输出可执行文件名为 app

  • -lsqlite3:链接 SQLite3 库

  • -lpthread:链接 POSIX 线程库

  • -ldl:链接动态加载库(Linux 上需要)

2. 示例

复制代码
#include <sqlite3.h>
#include <iostream>
#include <string>

class SQLiteDB {
private:
    sqlite3* db;
    
public:
    SQLiteDB() : db(nullptr) {}
    
    // 打开数据库
    bool open(const std::string& filename) {
        int rc = sqlite3_open(filename.c_str(), &db);
        if (rc != SQLITE_OK) {
            std::cerr << "无法打开数据库: " << sqlite3_errmsg(db) << std::endl;
            return false;
        }
        return true;
    }
    
    // 执行 SQL 语句
    bool execute(const std::string& sql) {
        char* errMsg = nullptr;
        int rc = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errMsg);
        if (rc != SQLITE_OK) {
            std::cerr << "SQL 错误: " << errMsg << std::endl;
            sqlite3_free(errMsg);
            return false;
        }
        return true;
    }
    
    // 查询数据(回调函数方式)
    static int callback(void* data, int argc, char** argv, char** colName) {
        for (int i = 0; i < argc; i++) {
            std::cout << colName[i] << " = " << (argv[i] ? argv[i] : "NULL") << std::endl;
        }
        std::cout << "--------" << std::endl;
        return 0;
    }
    
    // 带参数的查询
    bool query(const std::string& sql) {
        char* errMsg = nullptr;
        int rc = sqlite3_exec(db, sql.c_str(), callback, nullptr, &errMsg);
        if (rc != SQLITE_OK) {
            std::cerr << "查询错误: " << errMsg << std::endl;
            sqlite3_free(errMsg);
            return false;
        }
        return true;
    }
    
    // 使用预处理语句(防SQL注入)
    bool preparedInsert(const std::string& name, int age) {
        sqlite3_stmt* stmt;
        const char* sql = "INSERT INTO users (name, age) VALUES (?, ?)";
        
        int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
        if (rc != SQLITE_OK) {
            return false;
        }
        
        // 绑定参数
        sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_STATIC);
        sqlite3_bind_int(stmt, 2, age);
        
        // 执行
        rc = sqlite3_step(stmt);
        
        // 清理
        sqlite3_finalize(stmt);
        
        return rc == SQLITE_DONE;
    }
    
    // 关闭数据库
    void close() {
        if (db) {
            sqlite3_close(db);
            db = nullptr;
        }
    }
    
    ~SQLiteDB() {
        close();
    }
};

int main() {
    SQLiteDB database;
    
    // 打开数据库(如果不存在则创建)
    if (!database.open("test.db")) {
        return 1;
    }
    
    // 创建表
    database.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
    
    // 插入数据
    database.execute("INSERT INTO users (name, age) VALUES ('张三', 25)");
    database.execute("INSERT INTO users (name, age) VALUES ('李四', 30)");
    
    // 使用预处理语句插入
    database.preparedInsert("王五", 28);
    
    // 查询数据
    std::cout << "查询结果:" << std::endl;
    database.query("SELECT * FROM users");
    
    // 更新数据
    database.execute("UPDATE users SET age = 26 WHERE name = '张三'");
    
    // 删除数据
    database.execute("DELETE FROM users WHERE age > 29");
    
    // 再次查询
    std::cout << "\n更新后的结果:" << std::endl;
    database.query("SELECT * FROM users");
    
    return 0;
}

3. 使用 C++ 封装库(简化复杂操作)

除了直接使用 C API,还可以使用 C++ 封装库:

SQLiteCpp(推荐)

复制代码
#include <SQLiteCpp/SQLiteCpp.h>
#include <iostream>

int main() {
    try {
        // 打开数据库
        SQLite::Database db("test.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);
        
        // 执行 SQL
        db.exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
        
        // 插入数据
        SQLite::Statement insert(db, "INSERT INTO users (name, age) VALUES (?, ?)");
        insert.bind(1, "张三");
        insert.bind(2, 25);
        insert.exec();
        
        // 查询数据
        SQLite::Statement query(db, "SELECT * FROM users");
        while (query.executeStep()) {
            int id = query.getColumn(0);
            std::string name = query.getColumn(1);
            int age = query.getColumn(2);
            std::cout << "id: " << id << ", name: " << name << ", age: " << age << std::endl;
        }
        
    } catch (std::exception& e) {
        std::cerr << "SQLite 异常: " << e.what() << std::endl;
    }
    
    return 0;
}

4. 编译命令

直接编译:

复制代码
# 使用系统库
g++ main.cpp -o app -lsqlite3 -lpthread -ldl

# 使用 SQLiteCpp
g++ main.cpp -o app -lsqlite3 -lSQLiteCpp -lpthread -ldl

CMake 配置:

复制代码
cmake_minimum_required(VERSION 3.10)
project(SQLiteExample)

find_package(SQLite3 REQUIRED)
find_package(SQLiteCpp REQUIRED)  # 如果使用 SQLiteCpp

add_executable(app main.cpp)
target_link_libraries(app SQLite::SQLite3)
target_link_libraries(app SQLiteCpp)  # 如果使用 SQLiteCpp

5. 主要特点

  1. 零配置:无需服务器,单文件数据库

  2. 事务支持:ACID 兼容

  3. 跨平台:支持 Windows、Linux、macOS 等

  4. 轻量级:库文件小,资源占用少

  5. 丰富的 API :提供完整的 SQL 支持

    SQL = Structured Query Language(结构化查询语言))

6.与其他数据库的扩展名对比

数据库系统 常见扩展名 说明
SQLite .db, .sqlite, .sqlite3 单文件嵌入式数据库
MySQL .sql, .frm, .ibd 需要服务器,多文件
PostgreSQL 无特定扩展名 目录结构,无单文件
SQL Server .mdf, .ldf 微软数据库系统
Oracle .dbf, .ora 企业级数据库
**SQLite (加密)**​ .db, .sqlite 内容加密,扩展名相同
Access .mdb, .accdb 微软 Access 数据库
相关推荐
爬也要爬着前进18 分钟前
redis主从搭建
数据库·redis·缓存
@Mike@37 分钟前
02-数据库学习笔记(SQL引擎)
数据库·笔记·学习
王维同学1 小时前
[自学][Windows C++]RunOnceEx 注册表分组键的安全遍历
c++·windows·安全·开源
笃行3502 小时前
国产化落地避坑 · 干货向|Oracle 迁金仓 KES,我把外连接消除排在隐性陷阱第一位
数据库
Scott9999HH2 小时前
告别流量波动玄学!从法拉第电磁定律到底层 C/C++ 流量累积算法,深度解密工业级电磁流量计选型与开发
c语言·c++·算法
老纪的技术唠嗑局2 小时前
花一年时间整理出的:AI 数据库混合搜索入门实践
数据库
脱胎换骨-军哥3 小时前
C++/Rust无缝互操作:混合系统新常态
开发语言·c++·rust
川石课堂软件测试3 小时前
安全测试|常见SQL注入攻击方式、实例及预防
服务器·数据库·sql·功能测试·测试工具·安全·单元测试
笃行3503 小时前
国产化落地避坑 · 干货向|迁移后那条「测试能过、一上生产就查空」的 SQL,多半栽在 WHERE 函数顺序上
数据库
蓝田~4 小时前
MySQL慢查询怎么优化?B+Tree索引原理+MVCC读不阻塞写+EXPLAIN执行计划,从5秒到0.05秒
数据库·mysql