
🎬 个人主页 :艾莉丝努力练剑
❄专栏传送门 :《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:

文章目录
- [1 ~> SQLite 基础概念](#1 ~> SQLite 基础概念)
-
- [1.1 SQLite 存储类](#1.1 SQLite 存储类)
- [1.2 亲和类型 (Affinity)](#1.2 亲和类型 (Affinity))
-
- [1.2.1 五种亲和类型](#1.2.1 五种亲和类型)
- [1.2.2 建表类型名与亲和类型映射](#1.2.2 建表类型名与亲和类型映射)
- [1.3 SQLite 常用 SQL 语法分类](#1.3 SQLite 常用 SQL 语法分类)
- [2 ~> SQLite C/C++ 开发环境](#2 ~> SQLite C/C++ 开发环境)
-
- [2.1 开发依赖](#2.1 开发依赖)
- [2.2 编译链接命令](#2.2 编译链接命令)
-
- [2.2.1 GCC/G++ 命令](#2.2.1 GCC/G++ 命令)
- [2.2.2 Makefile](#2.2.2 Makefile)
- [2.2.3 CMakeLists.txt](#2.2.3 CMakeLists.txt)
- [3 ~> SQLite C API 核心模块](#3 ~> SQLite C API 核心模块)
-
- [3.1 数据库连接管理 API](#3.1 数据库连接管理 API)
-
- [3.1.1 sqlite3_open](#3.1.1 sqlite3_open)
- [3.1.2 sqlite3_close](#3.1.2 sqlite3_close)
- [3.1.3 sqlite3_errmsg](#3.1.3 sqlite3_errmsg)
- [3.2 SQL 预处理编译 API(prepare‑v2)](#3.2 SQL 预处理编译 API(prepare‑v2))
-
- [3.2.1 sqlite3_prepare_v2](#3.2.1 sqlite3_prepare_v2)
- [3.2.2 SQL 占位符(参数绑定)](#3.2.2 SQL 占位符(参数绑定))
- [3.3 参数绑定 API(bind 系列)](#3.3 参数绑定 API(bind 系列))
-
- [3.3.1 sqlite3_bind_int64](#3.3.1 sqlite3_bind_int64)
- [3.3.2 sqlite3_bind_text](#3.3.2 sqlite3_bind_text)
- [3.4 SQL 执行 API](#3.4 SQL 执行 API)
-
- [3.4.1 sqlite3_exec](#3.4.1 sqlite3_exec)
- [3.4.2 sqlite3_step](#3.4.2 sqlite3_step)
- [3.5 查询结果读取 API(column 系列)](#3.5 查询结果读取 API(column 系列))
-
- [3.5.1 sqlite3_column_text](#3.5.1 sqlite3_column_text)
- [3.6 资源释放 API](#3.6 资源释放 API)
-
- [3.6.1 sqlite3_finalize](#3.6.1 sqlite3_finalize)
- [4 ~> 标准 C 代码示例](#4 ~> 标准 C 代码示例)
-
- [4.1 数据库打开关闭示例](#4.1 数据库打开关闭示例)
- [4.2 sqlite3_exec 创建表示例](#4.2 sqlite3_exec 创建表示例)
- [4.3 prepare‑bind‑step‑finalize 完整流程(预处理插入)](#4.3 prepare‑bind‑step‑finalize 完整流程(预处理插入))
- [5 ~> API 开发关键易错点总结](#5 ~> API 开发关键易错点总结)
- [6 ~> 安全重点:SQL 注入防护](#6 ~> 安全重点:SQL 注入防护)
- 结尾

1 ~> SQLite 基础概念
1.1 SQLite 存储类
SQLite 是弱类型数据库,存储类比声明的数据类型优先级更高,一条记录的每个字段可以拥有不同存储类型。
INTEGER:带符号整数,占用 1/2/3/4/6/8 字节,根据数值大小自动选择存储空间。REAL:8 字节 IEEE754 双精度浮点。TEXT:文本字符串,支持 UTF‑8、UTF‑16BE、UTF‑16LE 编码。BLOB:原始二进制字节流,输入什么就存储什么,不做任何转换。NULL:空值。
1.2 亲和类型 (Affinity)
亲和类型:建表时给列声明类型,插入数据时 SQLite 按照亲和规则对输入数据做隐式转换;不会强制限制存储类。
1.2.1 五种亲和类型
TEXT:插入数值会先转为文本再存储;NULL、BLOB 不转换。NUMERIC:文本插入时,如果转换为 INTEGER/REAL 无损可逆,则转换;否则保持 TEXT。"30000.0"可以无损转为整数时,存储为 INTEGER。NULL/BLOB 原样保存。INTEGER:转换规则等价NUMERIC,区别仅在CAST强制类型转换表达式行为。REAL:转换规则等价NUMERIC,不会把 **"30000.0"**这类可转整数的文本转为 INTEGER,始终保存浮点。NONE:完全不做转换,输入是什么存储类就保存什么。
1.2.2 建表类型名与亲和类型映射
| 声明类型 | 亲和类型 |
|---|---|
| INT、INTEGER、TINYINT、SMALLINT、MEDIUMINT、BIGINT、UNSIGNED BIG INT、INT2、INT8 | INTEGER |
| CHARACTER(n)、VARCHAR(n)、TEXT | TEXT |
建表写的类型名仅用于推导亲和类型,不做严格类型约束,也不限制存储长度。
1.3 SQLite 常用 SQL 语法分类
- DML:
DELETE、SELECT、INSERT、UPDATE、LIKE、GLOB、LIMIT、ORDER BY、GROUP BY、HAVING、DISTINCT - DDL:
CREATE TABLE、ALTER、CREATE INDEX、CREATE VIEW、CREATE TRIGGER - 特殊语法:
PRAGMA、JOIN、UNION、NULL、别名、Autoincrement、VACUUM、日期时间函数、内置聚合函数、EXPLAIN、SQL 注入防护
2 ~> SQLite C/C++ 开发环境
2.1 开发依赖
- 头文件:
#include <sqlite3.h>,编译阶段依赖。 - 库文件:<libsqlite3.so/libsqlite3.a>,链接阶段依赖。
2.2 编译链接命令
2.2.1 GCC/G++ 命令
bash
# C程序编译链接
gcc test.c -o test -lsqlite3
# C++程序编译链接
g++ test.cpp -o test -lsqlite3
2.2.2 Makefile
makefile
my_program: main.cpp
g++ main.cpp -o my_program -lsqlite3
2.2.3 CMakeLists.txt
cmake
add_executable(my_program main.cpp)
target_link_libraries(my_program sqlite3)
3 ~> SQLite C API 核心模块
核心对象:
sqlite3*:数据库连接句柄sqlite3_stmt*:预处理语句句柄(编译后的 SQL 字节码对象) 返回值宏:SQLITE_OK= 操作成功;其他均为错误码。
3.1 数据库连接管理 API
3.1.1 sqlite3_open
c
int sqlite3_open(const char *filename, sqlite3 **ppDb);
- 功能:打开 / 创建数据库文件,得到数据库连接句柄。
- 参数
filename:数据库文件路径;传NULL或者"memory",创建内存数据库,会话结束数据全部销毁。文件不存在则自动创建空数据库文件。ppDb:输出参数,二级指针;函数调用成功后写入 sqlite3 连接句柄。
- 返回值:
SQLITE_OK成功,错误码失败。
3.1.2 sqlite3_close
c
int sqlite3_close(sqlite3* db);
- 功能:关闭数据库连接,释放连接占用资源。
- 约束:所有 sqlite3_stmt 预处理语句必须全部 finalize 销毁之后,才能正常 close ;仍有未完成预处理语句,返回
SQLITE_BUSY,关闭失败。 - 参数:数据库连接句柄
db。 - 返回值:
SQLITE_OK成功;SQLITE_BUSY繁忙。
3.1.3 sqlite3_errmsg
c
const char *sqlite3_errmsg(sqlite3* db);
- 功能:获取该连接上最近一次错误的英文错误描述字符串。
- 参数:数据库连接句柄。
- 返回值:只读字符串指针;下一次数据库调用会覆盖错误信息。
3.2 SQL 预处理编译 API(prepare‑v2)
3.2.1 sqlite3_prepare_v2
c
int sqlite3_prepare_v2(
sqlite3 *db,
const char *zSql,
int nByte,
sqlite3_stmt **ppStmt,
const char **pzTail
);
- 功能:将 SQL 文本编译为 SQLite 虚拟机字节码,生成预处理语句对象
sqlite3_stmt*;仅编译,不会执行 SQL。会做 SQL 语法校验,语法非法直接返回错误码。 - 参数
db:数据库连接句柄。zSql:原始 SQL 字符串。nByte:SQL 字节长度;传-1自动按\0计算字符串长度。ppStmt:输出参数,得到预处理语句句柄。pzTail:输出参数,SQL 字符串中未参与编译的剩余部分,业务代码几乎全部传NULL。
- 返回值:
SQLITE_OK编译成功,错误码编译失败。
3.2.2 SQL 占位符(参数绑定)
预处理语句支持两种占位符,用于防 SQL 注入,复用编译后的字节码,循环批量插入效率极高。
- 问号占位符
?:索引从1 开始。
sql
insert into student(name,gender,age,gap) values(?,?,?,?);
- 命名占位符
:varname:
sql
insert into student(name,gender,age,gap) values(:name,:gender,:age,:gap);
注意:绑定 API 的 index 参数从 1 开始计数 ;后续读取查询结果
sqlite3_column_xxx列下标从 0 开始计数,极易混淆。
3.3 参数绑定 API(bind 系列)
bind 系列:给预处理语句占位符填充运行时数据;必须在
sqlite3_step之前调用。
3.3.1 sqlite3_bind_int64
c
int sqlite3_bind_int64(sqlite3_stmt* pStmt, int index, sqlite3_int64 value);
- 功能:绑定 64 位整型数据到指定占位符。
- 参数
pStmt:预处理语句句柄。index:占位符序号,起始为 1。value:待绑定 64 位整数。
- 返回值:
SQLITE_OK绑定成功。
3.3.2 sqlite3_bind_text
c
int sqlite3_bind_text(
sqlite3_stmt* pStmt,
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绑定成功。
其他 bind 系列:
sqlite3_bind_double、sqlite3_bind_blob、sqlite3_bind_null。
3.4 SQL 执行 API
3.4.1 sqlite3_exec
c
int sqlite3_exec(
sqlite3* db,
const char *sql,
int (*callback)(void*, int argc, char** argv, char** azColName),
void *arg,
char **errmsg
);
- 功能:直接执行一条或多条 SQL 字符串,内部封装 prepare‑step‑finalize 整套流程。
- 使用场景:适合无返回结果集 操作:
CREATE TABLE、INSERT、DROP;也可以执行 SELECT,通过回调接收每行数据。 - 参数
db:数据库连接。sql:多条 SQL 拼接字符串。callback:每行记录回调函数指针;不需要结果回调传NULL。arg:透传给 callback 第一个参数。argc:当前行列数量。argv[]:每一列的值字符串指针。azColName[]:每一列字段名字符串指针。
errmsg:输出错误字符串指针;出错后必须调用sqlite3_free(*errmsg)释放内存。
- 返回值:
SQLITE_OK全部 SQL 执行成功。
3.4.2 sqlite3_step
c
int sqlite3_step(sqlite3_stmt *pStmt);
- 功能:推进、执行预处理语句;循环调用获取查询结果行。
- 返回值
SQLITE_ROW:读到一行有效结果,此时可以调用sqlite3_column_xxx读取该行各列数据。SQLITE_DONE:SQL 语句全部执行完毕,没有更多行。- 其他:错误码。
对于 SELECT 查询:循环调用
sqlite3_step直到返回SQLITE_DONE,每一次返回SQLITE_ROW代表一行记录就绪。
3.5 查询结果读取 API(column 系列)
3.5.1 sqlite3_column_text
c
const unsigned char *sqlite3_column_text(sqlite3_stmt* pStmt, int iCol);
- 功能:读取当前 step 行指定列文本数据。
- 参数:
iCol列下标,从 0 开始计数。 - 返回值:只读 unsigned char 字符串指针;指针有效期截止到下一次
sqlite3_step/sqlite3_finalize调用。
配套读取接口:
sqlite3_column_int、sqlite3_column_double、sqlite3_column_blob、sqlite3_column_bytes。
3.6 资源释放 API
3.6.1 sqlite3_finalize
c
int sqlite3_finalize(sqlite3_stmt *pStmt);
- 功能:销毁预处理语句对象,释放 stmt 对象全部资源。
- 约束:所有 sqlite3_stmt 对象必须调用 finalize 释放,否则会造成资源泄露;close 之前必须全部 finalize 完成。
- 返回值:
SQLITE_OK成功。
4 ~> 标准 C 代码示例
4.1 数据库打开关闭示例
c
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
sqlite3 *db;
int rc;
/* 打开数据库,不存在则创建test.db */
rc = sqlite3_open("test.db", &db);
if (rc != SQLITE_OK)
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(EXIT_FAILURE);
}
fprintf(stdout, "Opened database successfully\n");
/* 业务操作... */
/* 关闭数据库连接 */
sqlite3_close(db);
return 0;
}
4.2 sqlite3_exec 创建表示例
c
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
/* exec查询回调函数 */
static int callback(void *NotUsed, int argc, char** argv, char** azColName)
{
int i;
for(i = 0; i < argc; i++)
{
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main(int argc, char* argv[])
{
sqlite3 *db;
char *zErrMsg = NULL;
int rc;
const char* sql =
"CREATE TABLE COMPANY("
"ID INT PRIMARY KEY NOT NULL,"
"NAME TEXT NOT NULL,"
"AGE INT NOT NULL,"
"ADDRESS CHAR(50),"
"SALARY REAL);";
rc = sqlite3_open("test.db", &db);
if(rc != SQLITE_OK)
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(EXIT_FAILURE);
}
/* 执行建表SQL */
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
if(rc != SQLITE_OK)
{
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
else
{
fprintf(stdout, "Table created successfully\n");
}
sqlite3_close(db);
return 0;
}
4.3 prepare‑bind‑step‑finalize 完整流程(预处理插入)
c
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
int main(void)
{
sqlite3 *db;
sqlite3_stmt *stmt;
int rc;
const char* sql = "insert into student(name, gender, age, gap) values(?,?,?,?);";
rc = sqlite3_open("test.db", &db);
if(rc != SQLITE_OK)
{
fprintf(stderr, "open db failed: %s\n", sqlite3_errmsg(db));
return 1;
}
/* 1.编译SQL生成预处理stmt */
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if(rc != SQLITE_OK)
{
fprintf(stderr, "prepare failed: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}
/* 2.绑定参数,index从1开始 */
sqlite3_bind_text(stmt, 1, "zhangsan", -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, "male", -1, SQLITE_STATIC);
sqlite3_bind_int64(stmt, 3, 18);
sqlite3_bind_double(stmt, 4, 3.5);
/* 3.执行 */
rc = sqlite3_step(stmt);
if(rc == SQLITE_DONE)
{
printf("insert ok\n");
}
else
{
fprintf(stderr, "step error: %s\n", sqlite3_errmsg(db));
}
/* 4.释放预处理语句资源 */
sqlite3_finalize(stmt);
sqlite3_close(db);
return 0;
}
5 ~> API 开发关键易错点总结
- 索引两套规则极易混淆
- bind 绑定占位符序号:从 1 开始
- column 读取查询结果列号:从 0 开始
- 资源生命周期
sqlite3_stmt必须调用sqlite3_finalize释放;未 finalize 直接sqlite3_close返回SQLITE_BUSY关闭失败。sqlite3_exec出错返回的errmsg必须使用sqlite3_free释放堆内存,不能直接 free。
- 两种执行 API 选型
sqlite3_exec:适合一次性简单 SQL,适合 DDL、批量无返回 DML;多条 SQL 字符串一次性执行。prepare‑bind‑step‑finalize:适合循环批量插入、动态参数查询,有效防御 SQL 注入攻击,性能更好。
sqlite3_bind_text的 destructor 参数SQLITE_STATIC:字符串生命周期长于 stmt,SQLite 不接管内存。SQLITE_TRANSIENT:SQLite 复制字符串副本,原始字符串可以立即释放。
- 内存数据库:
sqlite3_open(":memory:", &db),会话结束数据全部丢失,不会落盘磁盘文件。 - SQLite 是弱类型数据库,列声明类型仅决定亲和转换规则,不强制限制字段存储类。
6 ~> 安全重点:SQL 注入防护
- 禁止字符串拼接用户输入直接拼接进 SQL 语句。
- 正确方案:使用
sqlite3_prepare_v2预处理 + bind 绑定占位符参数,用户输入交给 bind 接口处理,自动转义。
c
// 错误!拼接用户输入,存在SQL注入风险
char sql_buf[256];
sprintf(sql_buf, "select * from user where name = '%s'", user_input);
安全写法: 使用
?占位符,sqlite3_bind_text绑定用户输入。
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ### 艾莉丝努力练剑 C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主 *** ** * ** *** 👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。 ❤️ 【点赞】 让优质内容被更多人看见,让知识传递更有力量。 ⭐ 【收藏】 把核心知识点存好,在需要时随时查、随时用。 💬 【评论】 分享你的经验或疑问,评论区一起交流避坑! 不要忘记给博主"一键四连"哦! "今日练剑达成!"
"技术之路难免有困惑,但同行的人会让前进更有方向。" |
结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主"一键四连"哦!
往期回顾:
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა
