参考引用
- SQLite 权威指南(第二版)
- SQLite3 入门
1. 接口基本使用
- SQLite C API 接口在线文档
1.1 打开数据库文件
- 返回值
- 成功返回 0 (SQLITE_OK),失败返回 1 (SQLITE_ERROR)
- 参数
- const char *filename 数据库文件路径
- sqlite3 **ppDb 打开数据库得到的数据库句柄
int sqlite3_open(const char *filename, sqlite3 **ppDb);
1.2 操作数据(执行 SQL 语句)
- 返回值
- 成功返回 0 (SQLITE_OK),失败返回 1 (SQLITE_ERROR)
- 参数
- sqlite3* 数据库句柄
- const char *sql 要执行的sql语句
- sqlite_callback 回调函数
- void * 给回调函数的参数
- char **errmsg 存储错误
- 最后要自己通过 sqlite3_free(errmsg); 释放该处内存空间
int sqlite3_exec(sqlite3*,const char *sql,sqlite_callback,void *,char **errmsg);
1.3 关闭数据库文件
- 返回值
- 成功返回 0 (SQLITE_OK),失败返回 1 (SQLITE_ERROR)
- 参数
- sqlite3* 数据库句柄
int sqlite3_close(sqlite3*);
1.4 接口基本使用示例
将 sqlite3.h 和 sqlite3.c 拷贝到与 main.c 同级目录下
- main.c
#include <stdio.h>
#include <sqlite3.h>
int main() {
// 1.打开数据库
sqlite3 *ppdb = NULL;
int ret = sqlite3_open("myapi.db", &ppdb);
if (ret != SQLITE_OK) {
perror("open failed");
return -1;
}
// 2.创建一个表格
const char *create_sql = "create table if not exists apitest (id int, name text);";
char *errmsg = NULL; // 存储错误
ret = sqlite3_exec(ppdb, create_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
printf("%s\n", errmsg);
}
sqlite3_free(errmsg);
// 插入数据
const char *insert_sql = "insert into apitest values(0,'aaa');";
ret = sqlite3_exec(ppdb, insert_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
printf("%s\n", errmsg);
}
sqlite3_free(errmsg); // 释放内存空间
// 3.关闭数据库
ret = sqlite3_close(ppdb);
return 0;
}
- 调用 Sqlite Expert 查看上述代码编译后生成的 myapi.db 数据库文件
2. 接口查询操作
2.1 回调查询
- 回调函数:用户数据库查询
int (*sqlite3_callback)(void*, int, char**, char**); int LoadMyInfo(void * para, int n_column, char ** column_value, char ** column_name )
- main.c
#include <stdio.h>
#include <sqlite3.h>
// 回调函数是根据查询的数据:有多少行就被调用多少次
// 这个函数调用次数与查询的行数一致,必须返回 0
/* 参数
arg 由 sqlite3_exec() 第四个参数传递过来
int col 查询到的数据的列数
char **values 一行数据有 cols 列
char **names 一行字段名
*/
int callback(void *arg, int cols, char **values, char **names) {
static int flag = 1;
if (flag == 1) {
for (int i = 0; i < cols; i++) {
printf("%s\t", names[i]);
}
printf("\n");
flag = 0;
}
for (int i = 0; i < cols; i++) {
printf("%s\t", values[i]);
}
printf("\n");
return 0;
}
int main() {
// 1.打开数据库
sqlite3 *ppdb = NULL;
int ret = sqlite3_open("myapi.db", &ppdb);
if (ret != SQLITE_OK) {
perror("open failed");
return -1;
}
// 2.创建一个表格
const char *create_sql = "create table if not exists apitest (id int, name text);";
char *errmsg = NULL; // 存储错误
ret = sqlite3_exec(ppdb, create_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
printf("%s\n", errmsg);
}
sqlite3_free(errmsg);
// 插入数据
const char *insert_sql = "insert into apitest values(0,'aaa');";
ret = sqlite3_exec(ppdb, insert_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
printf("%s\n", errmsg);
}
sqlite3_free(errmsg);
// 执行查询语句
const char *select_sql = "select * from apitest;";
ret = sqlite3_exec(ppdb, select_sql, callback, NULL, &errmsg);
// 3.关闭数据库
ret = sqlite3_close(ppdb);
return 0;
//return 1; // 只查询一次便返回
}
- 控制台输出
id name 0 aaa 0 aaa 0 aaa
2.2 非回调查询
- 返回值
- 成功返回 0 (SQLITE_OK),失败返回 1 (SQLITE_ERROR)
- 参数
- sqlite3* 数据库句柄
- const char *sql sql 查询语句
- char ***resultp 查询的到的数据表
- int *nrow 查到数据表的行
- int *ncolumn 查到的数据表的列
- char **errmsg 存储错误
int sqlite3_get_table(sqlite3*,const char *sql,char ***resultp,int *nrow,int *ncolumn,char **errmsg);
- 示例
#include <stdio.h>
#include <sqlite3.h>
int main() {
// 1.打开数据库
sqlite3 *ppdb = NULL;
int ret = sqlite3_open("myapi.db", &ppdb);
if (ret != SQLITE_OK) {
perror("open failed");
return -1;
}
// 2.创建一个表格
const char *create_sql = "create table if not exists apitest2 (id int, name text);";
char *errmsg = NULL; // 存储错误
ret = sqlite3_exec(ppdb, create_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
printf("%s\n", errmsg);
}
sqlite3_free(errmsg);
// 插入数据
const char *insert_sql = "insert into apitest2 values(1,'bbb');";
ret = sqlite3_exec(ppdb, insert_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
printf("%s\n", errmsg);
}
sqlite3_free(errmsg);
// 执行非回调查询
const char *select_sql = "select * from apitest2;";
char **resultp = NULL;
int row = 0;
int col = 0;
ret = sqlite3_get_table(ppdb, select_sql, &resultp, &row, &col, &errmsg);
if (ret != SQLITE_OK) {
printf("%s\n", errmsg);
}
for (int i = 0; i < row + 1; i++) {
for (int j = 0; j < col; j++) {
printf("%s\t", resultp[j +i * col]);
}
printf("\n");
}
// 使用后要释放内存空间
sqlite3_free(errmsg);
sqlite3_free_table(resultp);
// 3.关闭数据库
sqlite3_close(ppdb);
return 0;
}
- 控制台输出
id name 1 bbb 1 bbb 1 bbb
3. 接口数据绑定机制
-
录入的数据量很大的情况下通常使用数据绑定机制来加快数据插入速度,通常流程如下
// 1、准备 int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); // 2、绑定数据 int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, void(*)(void*)); int sqlite3_bind_double(sqlite3_stmt*, int, double); int sqlite3_bind_int(sqlite3_stmt*, int, int); int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); int sqlite3_bind_null(sqlite3_stmt*, int); int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding); int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); // 3、执行 int sqlite3_step(sqlite3_stmt*); // 4、如果循环插入数据(循环绑定) int sqlite3_reset(sqlite3_stmt *pStmt); // 5、释放 int sqlite3_finalize(sqlite3_stmt *pStmt);
-
直接插入数据和绑定插入数据对比
#include <stdio.h> #include <sqlite3.h> #include <time.h> int main() { // 打开数据库 sqlite3 *ppdb = NULL; int ret = sqlite3_open("my.db", &ppdb); // 如果存在就直接打开,不存在就创建 //int ret = sqlite3_open(":memory:", &ppdb); // 不会创建文件,直接在内存中操作,关闭后就自动清除(临时数据库) if (ret != SQLITE_OK) { perror("open failed"); return -1; } // 创建一个表格 const char *create_sql = "create table if not exists test(id int, name text);"; char *errmsg = NULL; // 存储错误 ret = sqlite3_exec(ppdb, create_sql, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { printf("%s\n", errmsg); } sqlite3_free(errmsg); // 直接插入数据和绑定插入数据对比 // 1、直接插入数据 (分析---编译---执行) char insert_sql[128]={0}; for(int i = 0; i < 1000; i++) { sprintf(insert_sql, "insert into test values(%d, %d)", i, i*100); ret = sqlite3_exec(ppdb, insert_sql, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { printf("%s", errmsg); } } // 2、绑定插入数据 // 创建 sqlite3_stmt sqlite3_stmt *stmt = NULL; // ?表示这两个值是用来绑定的数据 char insert[] = "insert into test values(?,?)"; // 绑定位置顺序从 1 开始 sqlite3_prepare(ppdb, insert, sizeof(insert), &stmt, NULL); // 绑定数据 for (int i = 0; i < 1000; i++) { sqlite3_bind_int(stmt, 1, i); sqlite3_bind_int(stmt, 2, i*200); // 执行插入 sqlite3_step(stmt); sqlite3_reset(stmt); // 重置 } // 释放 sqlite3_finalize(stmt); sqlite3_close(ppdb); // 关闭数据库 return 0; }
4. 接口事务机制
-
事务机制可用于提高数据的操作效率
- 事务机制是在内存中操作,可以在内存中进行 insert、update、delete 等操作,操作完成后直接提交到数据库中
- 创建一个事务,后面一系列操作全部在内存中完成,当提交事务时才会去写文件
- 但如果突然断电等其他突发情况下,使用事务机制进行的操作将会不复存在
-
事务回滚
sqlite> select * from device; 0|led|1|0 1|led1|0|0 2|led2|2|0 3|led3|0|0 sqlite> begin; # 开始事务(后面的操作都不在数据库中操作) sqlite> update device set status=100; # 修改数据 sqlite> select * from device; 0|led|100|0 1|led1|100|0 2|led2|100|0 3|led3|100|0 sqlite> rollback; # 回滚到 begin 前位置 sqlite> select * from device; 0|led|1|0 1|led1|0|0 2|led2|2|0 3|led3|0|0 sqlite>
-
事务提交
sqlite> begin; sqlite> select * from device; 0|led|1|0 1|led1|0|0 2|led2|2|0 3|led3|0|0 sqlite> update device set status=123; sqlite> select * from device; 0|led|123|0 1|led1|123|0 2|led2|123|0 3|led3|123|0 sqlite> commit; # 提交到数据库中,下行的回滚操作将无效 sqlite> rollback; Error: cannot rollback - no transaction is active
-
如果没有 begin 开始,直接执行 sql 语句是自动提交事务
-
用 begin 开始事务,后执行(insert, delete, update)事务需要通过 commit 提交
// 开始事务 ret = sqlite3_exec(ppdb, "begin", NULL, NULL, NULL); // 执行sql语句 可以通过sqlite3_exec, 绑定机制插入数据 // 提交事务 ret = sqlite3_exec(ppdb, "commit", NULL, NULL, NULL);