SQLite3 数据库学习(三):SQLite C API 接口详解

本文详细介绍了SQLite3的接口使用方法,包括打开数据库、执行SQL语句、数据操作(回调和非回调)、数据绑定以及事务机制。通过实例展示了如何创建数据库、插入数据和执行查询,以及如何处理事务以提高数据操作效率。
摘要由CSDN通过智能技术生成

参考引用

1. 接口基本使用

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);
    
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值