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

参考引用

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端js,reduce归并操作图解

// 数组reduce方法// arr.reduce(function(上一次值, 当前值){}, 初始值)const arr [1, 5, 8]// 1. 没有初始值 // const total arr.reduce(function (prev, current) {// return prev current// })// console.log(total)// 2. 有初始值// const total arr.reduce(functi…

15:00进去,15:08就出来了,问的问题太变态了。

前不久刚从一家小自研出来&#xff0c;祸不单行&#xff0c;没想到的是在另一家公司也凉了。 到这家公司上班&#xff0c;每天加班是常态&#xff0c;但看在钱的面子上倒是还能忍受&#xff0c;毕竟给加班费&#xff0c;没想到前段时间突然出了通知&#xff0c;不仅加班费没了…

JVM虚拟机——类加载器(JDK8及以前,打破双亲委派机制)(JDK9之后的类加载器)

目录 1.自定义类加载器2.线程上下文类加载器3.OSGi模块化4.JDK9之后的类加载器5.类加载器总结 1.自定义类加载器 ⚫ 一个Tomcat程序中是可以运行多个Web应用的&#xff0c;如果这两个应用中出现了相同限定名的类&#xff0c;比如Servlet类&#xff0c;Tomcat要保证这两个类都能…

msvcp120.dll下载_msvcp120.dll文件丢失解决[dll系统文件修复]

msvcp120.dll是Microsoft Visual C库中的一个重要组件&#xff0c;属于Microsoft Visual C 2005 Redistributable Package。它提供了许多用于执行C程序所需的函数。Visual C是一款流行的集成开发环境&#xff08;IDE&#xff09;&#xff0c;广泛应用于游戏、视频和图形处理等领…

【计算机组成原理】绘制出纯整数(1字节)和纯小数的数轴

绘制出用原码、反码、补码表示纯整数(字节) 的数轴&#xff1a; 对于一字节的大小&#xff0c;原码和反码都只能表示255个数字&#xff0c;因为0占了2个符号数。而补码能表示256个数字&#xff0c;因为0和-0的补码是一样的。所以多出来一个符号数1000 0000能够表示-128所以&…

Android 摇一摇功能实现,重力加速度大于15

最近接到需求实现摇一摇需求&#xff0c;不过这个法律限制的很严格&#xff0c;属于敏感地带&#xff0c;实现后又被叫停了。 法律要求&#xff1a; 如果按照规定&#xff0c;操作时间不少于3s就基本没什么跳转了。 实现的话&#xff0c;只考虑了第一条&#xff0c;即&#…

JCJC错别字检测系统安装部署手册

本手册是针对 Ubuntu 服务器环境的安装使用说明。CentOS安装手册&#xff0c;请参考连接&#xff1a; JCJC错别字系统部署-腾讯云开发者社区-腾讯云 。 安装步骤&#xff1a; 第一步&#xff1a;安装 docker 离线方式在Ubuntu 18.04 上安装Docker &#xff0c;参考连接&am…

UniApp中的数据存储与获取指南

目录 介绍 数据存储方案 1. 本地存储 2. 数据库存储 3. 网络存储 实战演练 1. 本地存储实例 2. 数据库存储实例 3. 网络存储实例 注意事项与最佳实践 结语 介绍 在移动应用开发中&#xff0c;数据的存储和获取是至关重要的一部分。UniApp作为一款跨平台应用开发框架…

delete 与 truncate 命令的区别

直接去看原文 原文链接:【SQL】delete 与 truncate 命令的区别_truncate和delete的区别-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- 1. 相同点 二者都能删除表中的数据…

计算属性与watch的区别,fetch与axios在vue中的异步请求,单文本组件使用,使用vite创建vue项目,组件的使用方法

7.计算属性 7-1计算属性-有缓存 模板中的表达式虽然很方便,但是只能做简单的逻辑操作,如果在模版中写太多的js逻辑,会使得模板过于臃肿,不利于维护,因此我们推荐使用计算属性来解决复杂的逻辑 <!DOCTYPE html> <html lang"en"> <head><meta …

炫酷爱心表白

一、代码 <!DOCTYPE html> <!-- saved from url(0051)https://httishere.gitee.io/notion/v4/love-name.html --> <html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><title>&#x1f4…

11_聚类算法

文章目录 1 聚类1.1 什么是聚类1.2 相似度/距离公式1.3 聚类的思想 2 K-means算法2.1 K-means算法步骤2.2 K-means算法思考2.3 K-means算法优缺点 3 解决K-Means算法对初始簇心比较敏感的问题3.1 二分K-Means算法3.2 K-Means算法3.3 K-Means||算法3.4 Canopy算法3.4.1 Canopy算…

gradle PKIX path building failed

最近编译gradle项目的时候突然出错了,说是could not resolve org.springframework.boot.spring-boot-gradle-plugin:xxx 最后的错误是PKIX path building failed 这个错初一看是https的证书校验错误&#xff0c;然后网上搜了很多解决方案都不行&#xff0c;最后摸索出来是grad…

LTV预测算法从开发到上线,浅谈基于奇点云DataSimba的MLOps实践

今年8月&#xff0c;StartDT旗下GrowingIO分析云产品客户数据平台&#xff08;CDP&#xff09;正式上线了LTV预测标签。通过开箱即用的标签功能&#xff0c;分析师就能一键生成用户价值的预测结果&#xff0c;用于用户运营和价值分析。 LTV预测标签背后是怎样的算法&#xff1…

url找不到404的问题,url被拼接

今天遇到一个测试feign调用的功能&#xff0c;如图所示 先说结论 Controller换成RestController 将日志设置为debug模式 被DispatcherServlet FORWARD了 找到路径 对属性设置断点&#xff0c;看下是哪注进来的 我们再去找encodedPath 此处是undertow的源码&#xff0c;但是und…

systemverilog:interface中的modport用法

使用modport可以将interface中的信号分组并指定方向&#xff0c;方向是从modport连接的模块看过来的。简单示例如下&#xff1a; interface cnt_if (input bit clk);logic rstn;logic load_en;logic [3:0] load;logic [7:0] count;modport TEST (input clk, count,output rst…

Node.js 安装配置

文章目录 安装检测Node是否可用 安装 首先我们需要从官网下载Node安装包:Node.Js中文网,下载后双击安装没有什么特殊的地方&#xff0c;安装路径默认是C盘&#xff0c;不想安装C盘的话可以选择一下其他的盘符。安装完成以后可以不用配置环境变量&#xff0c;Node安装已经自动给…

正点原子阿尔法Linux开发板——MfgTool烧写工具烧写系统

WINDOWS系统下 前提准备 OTG、TTL的USB接口分别连接电脑 USB_OTG 用于烧写&#xff0c;USB_TTL 用于串口查看烧录进度 拨码拨至USB烧录——0100 0000 烧写 SECURE 软件连接串口CH340的COM&#xff08;软件安装激活&#xff09; 我的开发板是I.MX6ULL(EMMC)——双击"Li…

面向对象和原型/原型链学习

##构造函数执行的机制 函数的其中一个作用,就是构造函数. ###new关键字 1.创建一个对象; 2.这个对象的原型,可以看到这个Function 3.该对象,实现了这个构造函数的方法. 4.根据一些特定情况,返回: (1)如果没有返回值,就返回一个对象; (2)如果返回一个基本类型,则还是返回…

指针传2

几天没有写博客了&#xff0c;怎么说呢&#xff1f;这让我总感觉缺点什么&#xff0c;心里空落落的&#xff0c;你懂吧&#xff01; 好了&#xff0c;接下来开始我们今天的正题&#xff01; 1. ⼆级指针 我们先来看看代码&#xff1a; 首先创建了一个整型变量a&#xff0c;将…