【数据库】SQLite的基础使用

目录

[一、SQLite 介绍](#一、SQLite 介绍)

[二、Ubuntu 下 SQLite 安装与配置](#二、Ubuntu 下 SQLite 安装与配置)

[2.1 命令行工具与开发库安装](#2.1 命令行工具与开发库安装)

[2.2 编译链接配置](#2.2 编译链接配置)

[三、SQLite 命令行常用操作](#三、SQLite 命令行常用操作)

[3.1 核心点命令分类详解](#3.1 核心点命令分类详解)

数据库操作核心命令

表与结构操作核心命令

[3.2 增删查改演示](#3.2 增删查改演示)

[四、SQLite 核心 API](#四、SQLite 核心 API)

[4.1 SQLite 核心 API 详解](#4.1 SQLite 核心 API 详解)

[4.1.1 数据库连接管理 API](#4.1.1 数据库连接管理 API)

[4.1.2 SQL 语句执行核心 API](#4.1.2 SQL 语句执行核心 API)


一、SQLite 介绍

SQLite 是一个开源、轻量级、零配置、无服务器、自包含、事务性、支持标准 SQL、跨平台的数据库管理系统,也是目前世界上使用最广泛的数据库引擎。

核心特性如下:

  • 开源:代码完全透明,免费供个人和商业使用,无版权顾虑
  • 轻量级:精简,编译后的库文件仅需几百 KB,对硬件资源要求极低
  • 零配置:无需安装、无需启动 / 停止服务进程、无需任何配置文件,开箱即用
  • 无服务器:没有独立的服务器进程,应用程序直接通过函数调用读写磁盘上的数据库文件,省去了进程间通信的额外开销
  • 自包含 :整个数据库(所有表、索引、数据、元信息)都存储在单个跨平台的.db 文件中,备份、迁移、复制只需要操作这一个文件,极其便捷
  • 事务性:完整支持 ACID(原子性、一致性、隔离性、持久性)事务特性,哪怕系统崩溃、意外断电,也能保证数据的完整性不被破坏
  • 支持标准 SQL:兼容绝大多数标准 SQL 语法,单数据库最高支持 128TB 存储
  • 跨平台:数据库文件可在 Windows、Linux、MacOS、Android、iOS 等几乎所有平台间无缝迁移,无兼容性问题
  • 简单易用 :开发时仅需引入一个sqlite3.h头文件和对应的库文件,学习成本低

基于以上特性,SQLite 被广泛应用于嵌入式系统与物联网终端、移动端 App 本地存储、桌面小型应用、开发原型快速验证、临时数据分析等场景。

二、Ubuntu 下 SQLite 安装与配置

SQLite 在 Ubuntu 系统下的安装很简单,通过 apt 包管理器即可完成,我们需要安装两个核心包:命令行工具(用于终端直接操作数据库)和 C/C++ 开发库(用于代码开发)。

2.1 命令行工具与开发库安装

bash 复制代码
# 安装SQLite3命令行客户端工具
sudo apt install sqlite3

# 安装SQLite3 C/C++开发包(含头文件、静态/动态库)
sudo apt install libsqlite3-dev

安装完成后,可通过以下命令查看开发库的安装路径,确认安装成功:

bash 复制代码
# 列出libsqlite3-dev软件包的所有文件与安装路径
dpkg -L libsqlite3-dev

执行后会输出核心文件的安装路径,关键文件包括:

  • 开发必需头文件:/usr/include/sqlite3.h/usr/include/sqlite3ext.h
  • 静态库:/usr/lib/x86_64-linux-gnu/libsqlite3.a
  • 动态库:/usr/lib/x86_64-linux-gnu/libsqlite3.so
  • pkg-config 配置文件:/usr/lib/x86_64-linux-gnu/pkgconfig/sqlite3.pc

2.2 编译链接配置

在 C/C++ 项目中使用 SQLite,编译时必须链接 sqlite3 库,这里提供两种主流构建方式的配置方案

  • 直接 g++ 编译(Makefile 写法)

    g++ main.cpp -o my_program -lsqlite3

  • CMake 项目配置(CMakeLists.txt 写法)

    target_link_libraries(${SDK_NAME} sqlite3)

其中-lsqlite3的作用是告诉编译器链接系统中的 sqlite3 动态库,确保代码中的 SQLite 函数调用能正常找到对应实现。

三、SQLite 命令行常用操作

安装完成后,我们可以直接在终端通过 sqlite3 命令操作数据库,这里先明确两个核心概念:

  • 点命令 :以.开头,是 sqlite3 终端的专属命令,无需分号结尾,用于数据库、表的元信息操作
  • 标准 SQL 语句:兼容通用 SQL 语法,必须以分号结尾,用于数据的增删改查

3.1 核心点命令分类详解

数据库操作核心命令
命令 功能说明 实操示例
.open 文件名 打开指定数据库文件;若文件不存在,则自动创建 .open student.db
.databases 显示当前所有已连接的数据库,查看数据库状态 .databases
.attach 文件名 as 别名 附加一个额外的数据库文件到当前连接 .attach archive.db as archive
.backup 文件名 备份当前数据库到指定文件 .backup backup.db
.restore 文件名 从备份文件恢复数据库 .restore recovery.db
.quit / .exit 退出 SQLite3 终端 .quit
.help 查看所有命令的帮助信息 .help
表与结构操作核心命令
命令 功能说明 实操示例
.tables 显示当前数据库中所有的表名 .tables
.schema [表名] 查看指定表的建表结构,不写表名则显示所有表结构 .schema students
.indexes [表名] 查看指定表的所有索引,不写表名则显示所有索引 .indexes students

3.2 增删查改演示

下面我们通过完整步骤,演示如何在终端创建学生数据库、建表、插入、查询、修改、删除全流程:

  • 进入 SQLite 交互终端

    sqlite3

执行后会进入sqlite>交互模式,所有操作均在此模式下执行。

  • 创建 / 打开数据库

    sqlite> .open student.db

执行后,会在当前目录创建student.db数据库文件,若文件已存在则直接打开。

  • 验证数据库连接

    sqlite> .databases

执行后会显示当前连接的数据库路径,确认数据库创建成功。

  • 创建学生表(标准 SQL 语句,必须以分号结尾)

    sqlite> CREATE TABLE students(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    age INTEGER,
    score REAL
    );

表结构说明:

  • id:整数类型,主键,自增,唯一标识每个学生

  • name:文本类型,非空约束,存储学生姓名

  • age:整数类型,存储学生年龄

  • score:浮点类型,存储学生成绩

  • 查看表结构,验证建表成功

    sqlite> .schema students

执行后会输出上述建表语句,确认表结构正确。

  • 插入测试数据

    sqlite> INSERT INTO students(name, age, score) VALUES
    ('张三', 18, 92.0),
    ('李四', 19, 93.5),
    ('王五', 18, 76.5);

  • 查询表中所有数据

    sqlite> SELECT * FROM students;

执行后输出结果:

复制代码
1|张三|18|92.0
2|李四|19|93.5
3|王五|18|76.5
  • 删除数据(删除成绩低于 80 分的学生)

    sqlite> DELETE FROM students WHERE score < 80;

  • 再次查询,验证删除结果

    sqlite> SELECT * FROM students;

执行后输出结果,王五的记录已被删除:

复制代码
1|张三|18|92.0
2|李四|19|93.5

四、SQLite 核心 API

4.1 SQLite 核心 API 详解

我们按功能将 API 分为数据库连接管理SQL 语句执行两大类。

4.1.1 数据库连接管理 API

这是所有操作的基础,负责数据库的打开、关闭与错误排查。

1. 打开数据库连接

复制代码
int sqlite3_open(const char *filename, sqlite3 **ppDb);
  • 功能:打开一个数据库连接,若指定的数据库文件不存在,则自动创建

  • 参数:

    • filename:数据库文件的路径(如"student.db"
    • ppDb:指向sqlite3*类型的指针,函数执行成功后,会将数据库连接句柄存入该指针
  • 返回值:执行成功返回SQLITE_OK,失败则返回对应的错误码
    2. 关闭数据库连接

    int sqlite3_close(sqlite3* db);

  • 功能:关闭已打开的数据库连接,释放所有相关资源

  • 参数:db:已打开的数据库连接句柄

  • 返回值:执行成功返回SQLITE_OK;若还有未完成的预处理语句,会返回SQLITE_BUSY
    3. 获取错误信息

    const char sqlite3_errmsg(sqlite3 db);

  • 功能:获取数据库连接最近一次操作的错误描述文本,用于调试排错

  • 参数:db:数据库连接句柄

  • 返回值:指向错误信息字符串的指针

4.1.2 SQL 语句执行核心 API

SQLite 执行 SQL 语句有两种主流方式:

  • 便捷方式:sqlite3_exec,适合无结果集的 SQL 语句(建表、插入、更新、删除)
  • 预处理方式:prepare+step+finalize,适合带参数的 SQL、有结果集的查询,可防止 SQL 注入,性能更优

(1)便捷方式

SQL 语句一键执行(sqlite3_exec)

复制代码
int sqlite3_exec(
    sqlite3* db, 
    const char *sql,
    int (*callback)(void*, int, char**, char**),
    void *arg,
    char **errmsg
);
  • 功能:执行一条或多条 SQL 语句,最适合无结果集的 DDL/DML 语句(CREATE、INSERT、UPDATE、DELETE)
  • 参数:
    • db:数据库连接句柄
    • sql:要执行的 SQL 语句字符串
    • callback:回调函数,每查询到一条结果记录就会调用一次,无结果集的语句可设为 NULL
    • arg:传递给回调函数第一个参数的自定义数据,无需求可设为 NULL
    • errmsg:用于接收错误信息,使用后必须通过sqlite3_free()释放内存
  • 返回值:执行成功返回SQLITE_OK,失败则返回错误码

(二)预处理方式

1. 预处理 SQL 语句(sqlite3_prepare_v2)

复制代码
int sqlite3_prepare_v2(
    sqlite3 *db,
    const char *zSql,
    int nByte,
    sqlite3_stmt **ppStmt,
    const char **pzTail
);
  • 功能:将 SQL 语句编译成预处理语句对象(stmt),为参数绑定和执行做准备,是防止 SQL 注入的核心
  • 参数:
    • db:数据库连接句柄
    • zSql:要编译的 SQL 语句文本,参数用 ? 占位
    • nByte:SQL 语句的字节长度,设为-1则自动计算到字符串结束符\0为止
    • ppStmt:输出参数,执行成功后会存入预处理语句句柄
    • pzTail:指向未使用的 SQL 部分的指针,通常设为 NULL
  • 返回值:编译成功返回SQLITE_OK,失败则返回错误码
    2. 参数绑定

API预处理语句中的 ?占位符,需要通过 bind 系列函数绑定具体值,参数序号从 1 开始

  • 绑定整数

    int sqlite3_bind_int64(sqlite3_stmt* stmt, int index, sqlite3_int64 value);

功能:向预处理语句的指定位置绑定 64 位整数值,普通 int 也可使用参数:index - 参数序号(从 1 开始),value - 要绑定的整数值返回值:成功返回SQLITE_OK,失败返回错误码

  • 绑定文本字符串

    int sqlite3_bind_text(
    sqlite3_stmt* stmt,
    int index,
    const char *value,
    int len,
    void(destructor)(void)
    );

功能:向预处理语句的指定位置绑定文本字符串参数:

  • index:参数序号(从 1 开始)
  • value:要绑定的字符串
  • len:字符串字节长度,-1则自动计算到\0结束
  • destructor:字符串内存销毁策略,常用两个值:
    • SQLITE_STATIC:SQLite 不会释放该字符串内存,适用于静态字符串 / 栈内存
    • SQLITE_TRANSIENT:SQLite 会复制该字符串的副本,适用于临时的堆内存字符串,无需手动管理生命周期返回值:成功返回SQLITE_OK,失败返回错误码

补充:还有sqlite3_bind_double(绑定浮点型)等 API,用法与上述一致,对应不同数据类型。
3. 执行预处理语句(sqlite3_step)

复制代码
int sqlite3_step(sqlite3_stmt *pStmt);
  • 功能:执行预处理语句,逐行获取结果集
  • 参数:pStmt:预处理语句句柄
  • 返回值:
    • SQLITE_ROW:查询到一行结果数据,数据已就绪,可读取
    • SQLITE_DONE:语句执行完成,无更多结果
    • 其他值:执行出错,对应错误码
      4. 读取结果集数据

sqlite3_step返回SQLITE_ROW时,可通过 column 系列函数读取当前行的列数据,列序号从 0 开始

复制代码
const unsigned char *sqlite3_column_text(sqlite3_stmt* stmt, int iCol);
  • 功能:读取指定列的文本类型数据
  • 参数:iCol:列序号(从 0 开始)
  • 返回值:指向文本数据的指针

补充:还有sqlite3_column_int(读取整数)、sqlite3_column_double(读取浮点数)等,用法一致。
5. 销毁预处理语句(sqlite3_finalize)

复制代码
int sqlite3_finalize(sqlite3_stmt *pStmt);
  • 功能:销毁预处理语句对象,释放所有关联的资源,所有 prepare 创建的 stmt,使用完必须调用此函数释放,否则会造成内存泄漏
  • 参数:pStmt:预处理语句句柄
  • 返回值:成功返回SQLITE_OK,失败返回错误码

(三)两种方式的综合示例

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

// 回调函数:用于处理 sqlite3_exec 的查询结果(C 链接,兼容 SQLite C 接口)
// 参数说明:
//   data: 自定义传入的数据(这里传输出流)
//   argc: 查询结果的列数
//   argv: 每列的数值(字符串形式)
//   azColName: 每列的列名
extern "C" int query_callback(void* data, int argc, char** argv, char** azColName)
{
    std::ostream& out = *static_cast<std::ostream*>(data);
    out << "查询结果行:";
    for (int i = 0; i < argc; ++i)
    {
        out << azColName[i] << "=" << (argv[i] ? argv[i] : "NULL") << " ";
    }
    out << std::endl;
    return 0; // 返回 0 表示继续处理下一行
}

int main()
{
    sqlite3* db = nullptr;
    char* err_msg = nullptr;
    int rc;

    // 1. 打开/创建 SQLite 数据库(内存数据库 :memory:,也可替换为文件路径如 "test.db")
    rc = sqlite3_open(":memory:", &db);
    if (rc != SQLITE_OK)
    {
        std::cerr << "打开数据库失败:" << sqlite3_errmsg(db) << std::endl;
        sqlite3_close(db);
        return -1;
    }
    std::cout << "数据库打开成功!" << std::endl;

    // ==================== 方式1:使用 sqlite3_exec 执行简易 SQL(无参数化) ====================
    std::cout << "\n----- 方式1:sqlite3_exec 简易执行 -----" << std::endl;

    // 1.1 创建表
    const char* create_sql = "CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);";
    rc = sqlite3_exec(db, create_sql, nullptr, nullptr, &err_msg);
    if (rc != SQLITE_OK)
    {
        std::cerr << "创建表失败:" << err_msg << std::endl;
        sqlite3_free(err_msg);
        sqlite3_close(db);
        return -1;
    }
    std::cout << "表创建成功!" << std::endl;

    // 1.2 插入数据(非参数化,直接拼接字符串,有 SQL 注入风险)
    const char* insert_sql = "INSERT INTO user (name, age) VALUES ('张三', 20);";
    rc = sqlite3_exec(db, insert_sql, nullptr, nullptr, &err_msg);
    if (rc != SQLITE_OK)
    {
        std::cerr << "插入数据失败:" << err_msg << std::endl;
        sqlite3_free(err_msg);
        sqlite3_close(db);
        return -1;
    }
    std::cout << "简易插入数据成功!" << std::endl;

    // 1.3 查询数据(通过回调函数处理结果)
    const char* select_sql = "SELECT * FROM user;";
    rc = sqlite3_exec(db, select_sql, query_callback, &std::cout, &err_msg);
    if (rc != SQLITE_OK)
    {
        std::cerr << "查询数据失败:" << err_msg << std::endl;
        sqlite3_free(err_msg);
        sqlite3_close(db);
        return -1;
    }

    // ==================== 方式2:预处理语句(参数化,安全高效) ====================
    std::cout << "\n----- 方式2:预处理语句(参数化执行) -----" << std::endl;

    sqlite3_stmt* stmt = nullptr;

    // 2.1 预处理插入(参数化,避免 SQL 注入)
    const char* insert_param_sql = "INSERT INTO user (name, age) VALUES (?, ?);";
    // 步骤1:编译 SQL 为预处理语句
    rc = sqlite3_prepare_v2(db, insert_param_sql, -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        std::cerr << "预处理插入语句失败:" << sqlite3_errmsg(db) << std::endl;
        sqlite3_close(db);
        return -1;
    }

    // 步骤2:绑定参数(? 占位符从 1 开始计数)
    std::string name = "李四";
    int age = 25;
    sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT); // 绑定字符串(-1 表示自动计算长度)
    sqlite3_bind_int(stmt, 2, age); // 绑定整数

    // 步骤3:执行语句
    rc = sqlite3_step(stmt);
    if (rc == SQLITE_DONE)
    {
        std::cout << "参数化插入数据成功!" << std::endl;
    }
    else
    {
        std::cerr << "参数化插入失败:" << sqlite3_errmsg(db) << std::endl;
    }

    // 步骤4:销毁预处理语句(必须释放)
    sqlite3_finalize(stmt);
    stmt = nullptr;

    // 2.2 预处理查询(参数化)
    const char* select_param_sql = "SELECT * FROM user WHERE age > ?;";
    rc = sqlite3_prepare_v2(db, select_param_sql, -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        std::cerr << "预处理查询语句失败:" << sqlite3_errmsg(db) << std::endl;
        sqlite3_close(db);
        return -1;
    }

    // 绑定查询参数(年龄大于 18)
    sqlite3_bind_int(stmt, 1, 18);

    // 执行查询并遍历结果
    std::cout << "参数化查询结果(age > 18):" << std::endl;
    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW)
    {
        // 读取列数据(列索引从 0 开始)
        int id = sqlite3_column_int(stmt, 0);
        const char* name = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        int age = sqlite3_column_int(stmt, 2);
        std::cout << "id=" << id << ", name=" << name << ", age=" << age << std::endl;
    }

    if (rc != SQLITE_DONE)
    {
        std::cerr << "参数化查询失败:" << sqlite3_errmsg(db) << std::endl;
    }

    // 释放查询的预处理语句
    sqlite3_finalize(stmt);

    // 2. 关闭数据库
    sqlite3_close(db);
    std::cout << "\n数据库连接已关闭" << std::endl;

    return 0;
}

官方学习资源:


感谢阅读,本文如有错漏,烦请斧正。

相关推荐
溜达的大象2 小时前
数据库选型不踩坑:从关系型到向量库的全景技术图谱
数据库
你才是臭弟弟2 小时前
window sever 2019 安装~时序数据库TDengine TSDB 和 视图工具dbeaver
数据库·时序数据库·tdengine
J超会运2 小时前
MySQL核心SQL语句速查宝典
数据库·mysql
Memory_荒年2 小时前
TiDB 单机部署与监控完整指南
运维·数据库·后端
殷紫川2 小时前
SQL 性能优化全解:从执行计划到底层逻辑,根治 99% 的慢 SQL 与规范落地
数据库·mysql
Memory_荒年2 小时前
TiDB:当 MySQL 遇上分布式,生了个“超级混血儿”
java·数据库·后端
asom222 小时前
DDD(领域驱动设计) 核心概念详解
java·开发语言·数据库·spring boot
ego.iblacat2 小时前
MySQL 数据库操作
数据库·mysql·adb
赵渝强老师2 小时前
【赵渝强老师】高斯数据库(openGauss)的逻辑存储结构
数据库·postgresql·opengauss·gaussdb·国产数据库·高斯数据库