目录
[一、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;
}
官方学习资源:
- SQLite 官方文档:https://sqlite.org/draft/index.html
- SQLite 教程:https://www.runoob.com/sqlite/sqlite-data-types.html
感谢阅读,本文如有错漏,烦请斧正。