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 数据库
相关推荐
进击的荆棘2 小时前
C++起始之路——模板进阶
开发语言·c++
一个有温度的技术博主2 小时前
Redis系列一:了解Nosql与关系型数据库
数据库·redis·nosql
云边云科技_云网融合2 小时前
百度首页中宇联云计算SD-AIoT:万物互联时代,从 “能连上” 到 “用得放心” 的技术革命
网络·数据库·人工智能
草莓熊Lotso2 小时前
Linux 进程间通信之 System V 共享内存:IPC 的原理与实战
linux·运维·服务器·c语言·数据库·c++·人工智能
尽兴-2 小时前
从零到精通:Redis 7 核心数据结构实战与单机部署指南
数据结构·数据库·redis·部署·redis7
q5431470872 小时前
Spring TransactionTemplate 深入解析与高级用法
java·数据库·spring
艾莉丝努力练剑2 小时前
【Linux:文件 + 进程】进程间通信进阶(1)
linux·运维·服务器·网络·c++·人工智能·进程
疋瓞2 小时前
C\C++\python对比_概览(1)
c语言·c++·python