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 数据库
相关推荐
qq_392690662 小时前
SQL报表查询标准规范_SQL书写规范优化
jvm·数据库·python
Vect__2 小时前
MySQL的数据类型和约束
android·数据库·mysql
八秒记忆的老男孩2 小时前
Sentinel5P的L1B级数据预处理(BD7和BD8)【20260427】
数据库·redis·缓存
ChoSeitaku2 小时前
5.MySQL表的约束|空属性|默认值|列描述|主键|自增长|唯一键|外键
android·数据库·mysql
S1998_1997111609•X2 小时前
滄集/㞯鎩.赫量被恶意篡改?|\^*仺\~:sall,sql=㶏齾bci.ji.app_sql=-heart{TCP.box}‘雧……㞋
网络·数据库·网络协议·百度·微信
2301_803875612 小时前
c++如何通过重定向streambuf流捕获标准错误输出并记录到运行日志【详解】
jvm·数据库·python
2301_795099743 小时前
HTML怎么创建时间轴布局_HTML结构化时间线写法【方法】
jvm·数据库·python
运气好好的3 小时前
CSS组件库如何快速扩展_通过Sass @extend继承基础布局
jvm·数据库·python
OYangxf3 小时前
基于epoll的单线程Reactor:Tinyredis的网络层实现
c++·redis
m0_613856293 小时前
Go install 命令失效原因解析与正确使用指南
jvm·数据库·python