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

news2024/10/7 0:03:57

参考引用

  • 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);
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1214023.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python 中的 tqdm() 方法

tqdm&#xff08;阿拉伯语"taqaddum"的缩写&#xff0c;意为"进展"&#xff09;是Python中一个用于在循环中显示进度条的库。它提供了一种简单而又灵活的方式来监测代码执行的进度&#xff0c;特别是在处理大量数据或耗时较长的任务时非常有用。 1、安装 …

第1章 走近Java【深入理解Java虚拟机:JVM高级特性与最佳实践(第三版)】

Java技术体系所包含的内容 Java技术发展的时间线 注释

C++11『右值引用 ‖ 完美转发 ‖ 新增类功能 ‖ 可变参数模板』

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; C修行之路 &#x1f383;操作环境&#xff1a; Visual Studio 2022 版本 17.6.5 文章目录 &#x1f307;前言&#x1f3d9;️正文1.右值引用1.1.什么是右值引用&#xff1f;1.2.move 转移资源1.3.左值引用 vs …

操作符——C语言初阶

一.算数操作符&#xff1a; - * / % 、-、*、/这四个运算符均可用于整数及浮点数的运算。 当使用/运算符时&#xff0c;如果两个操作数均为整型&#xff0c;那么执行整数除法&#xff0c;运算结果也为整型&#xff1b;如果两个操作数至少一个为浮…

Facebook账号运营技巧

Facebook作为全球知名的社交媒体平台之一&#xff0c;坐拥着庞大的用户群体&#xff0c;吸引大量的跨境电商加入&#xff0c;那么肯定就会有少部分的卖家对于Facebook账号运营不是很了解&#xff0c;下面小编将讲一下Facebook账号运营的一些小技巧。 1、明确目标受众 首先需要明…

32 _ 字符串匹配基础(上):如何借助哈希算法实现高效字符串匹配?

从今天开始,我们来学习字符串匹配算法。字符串匹配这样一个功能,我想对于任何一个开发工程师来说,应该都不会陌生。我们用的最多的就是编程语言提供的字符串查找函数,比如Java中的indexOf(),Python中的find()函数等,它们底层就是依赖接下来要讲的字符串匹配算法。 字符串…

【BIM入门实战】Revit图元的选择方式,总有一款适合你

Revit图元的五种常见选择方式,总有一款适合你。 文章目录 一、直接单击二、加选和减选三、连续框选四、按类别选择五、全选过滤选择操作可以在三维视图、平面视图等多种视图中进行。 一、直接单击 直接单击,即可选中某一个图元,如选择一个扶手。 二、加选和减选 按住ctrl键…

37 _ 贪心算法:如何用贪心算法实现Huffman压缩编码?

基础的数据结构和算法我们基本上学完了,接下来几节,我会讲几种更加基本的算法。它们分别是贪心算法、分治算法、回溯算法、动态规划。更加确切地说,它们应该是算法思想,并不是具体的算法,常用来指导我们设计具体的算法和编码等。 贪心、分治、回溯、动态规划这4个算法思想…

数据库表字段以表格形式写入Word

在项目的开发中&#xff0c;难免会有编写概要设计、详细设计文档的要求&#xff0c;而在这些文档中&#xff0c;不可避免的就是要把数据库表的字段信息以表格的形式体现出来。例如下面这种格式 表数量少点还可以一点点粘贴&#xff0c;多了的话真的会疯&#xff0c;所以自己编写…

【计算机网络笔记】DHCP协议

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

35 _ Trie树:如何实现搜索引擎的搜索关键词提示功能?

搜索引擎的搜索关键词提示功能,我想你应该不陌生吧?为了方便快速输入,当你在搜索引擎的搜索框中,输入要搜索的文字的某一部分的时候,搜索引擎就会自动弹出下拉框,里面是各种关键词提示。你可以直接从下拉框中选择你要搜索的东西,而不用把所有内容都输入进去,一定程度上…

C++二分查找算法:132 模式解法二枚举2

题目及解法一&#xff1a; https://blog.csdn.net/he_zhidan/article/details/134362273 分析 第一步&#xff0c;选择各3对应的1&#xff0c;如果有多个符合对应最小的1&#xff0c;记录num[0,j)中的最小值iMin&#xff0c;如果nums[j]大于iMin&#xff0c;则m3To1 [nums[j…

认知升级:模型与范式转换

你好&#xff0c;我是 EarlGrey&#xff0c;一名双语学习者&#xff0c;会一点编程&#xff0c;目前已翻译出版《Python 无师自通》、《Python 并行编程手册》等书籍。 点击上方蓝字关注我&#xff0c;持续获取编程干货、好书推荐和高效工具分享&#xff0c;一起提升认知和思维…

excel中正态分布函数NORM.DIST和NORMDIST,以及它们之间的区别

NORM.DIST和NORMDIST的区别 NORM.DIST和NORMDIST函数都可以返回正态分布的概率密度、或者正态累积分布。 根据微软官网上的说法&#xff0c;NORMDIST函数已经不建议使用了&#xff0c;它已经被一个或者几个新的函数代替&#xff08;例如NORM.DIST&#xff09;&#xff0c;这些…

Rust图形界面编程:egui平直布局

文章目录 平直布局with_layout 平直布局 在前面的示例中&#xff0c;已经用到了ui.horizontal用来布局&#xff0c;其特点是水平摆放控件。相应地&#xff0c;ui.vertical则是垂直摆放控件。根据控件的摆放顺序不同&#xff0c;这两个布局组件衍生出一系列布局函数 horizonta…

深入Rust:探索所有权和借用机制

大家好&#xff01;我是lincyang。 今天&#xff0c;我们将一起深入探索Rust语言中的一个核心概念&#xff1a;所有权和借用机制。 这些特性是Rust区别于其他语言的重要特点&#xff0c;它们在内存管理和并发编程中扮演着关键角色。 一、Rust所有权机制 1. 什么是所有权&#x…

Java --- JVM之StringTable

目录 一、String的基本特性 二、String的内存分配 2.1、String内存分布图 三、字符串拼接操作 3.1、字符串拼接操作底层原理 3.2、拼接操作与append操作效率对比 四、intern()方法 4.1、intern()效率 五、StringTable的垃圾回收 一、String的基本特性 1、String字符…

C++二分查找算法:数组中占绝大多数的元素

题目 设计一个数据结构&#xff0c;有效地找到给定子数组的 多数元素 。 子数组的 多数元素 是在子数组中出现 threshold 次数或次数以上的元素。 实现 MajorityChecker 类: MajorityChecker(int[] arr) 会用给定的数组 arr 对 MajorityChecker 初始化。 int query(int left, …

【算法】区间(差分约束)

题目 给定 n 个区间 [ai,bi] 和 n 个整数 ci。 你需要构造一个整数集合 Z&#xff0c;使得 ∀i∈[1,n]&#xff0c;Z 中满足 ai≤x≤bi 的整数 x 不少于 ci 个。 求这样的整数集合 Z 最少包含多少个数。 输入格式 第一行包含整数 n。 接下来 n 行&#xff0c;每行包含三个…

21 Linux 自带的LED驱动

一、Linux 自带 LED 驱动使能 其实 Linux 内核自带 LED 抢夺那个&#xff0c;但在此之前需要配置 Linux 驱动来使能 LED 驱动。 输入以下命令&#xff1a; cd linux/atk-mpl/linux/my_linux/linux-5.4.31 make menuconfig 根据以下路径找到 LED 驱动&#xff1a; → Device D…