核心C API

SQLite3 有八个函数用于实际处理连接、处理查询以及断开数据库连接的。其余都是为了完成特定的任务

一、查询封装

通过封装查询对数据库进行连接、断开、以及查询。

1.连接和断开
执行SQL命令之前,首先要连接数据库(打开数据库),断开连接时候断开数据库。
打开数据库函数:sqlite_open_v2()、sqlite3_open()、sqlite3_open16()。

函数:int sqlite_open_v2(const char *filename, sqlite3 **ppdb, int flag, const char *zvfs);
参数:filename:数据库名,如果为null,则创建一个临时文件,断开后就删除ppdb:SQLite数据库句柄,代表数据库的连接。flag:标志:SQLITE_OPEN_READONLY:只读模式打开数据库,文件不存在则返回错误。SQLITE_OPEN_READWRITE:读写模式打开数据库,文件不存在则返回错误。SQLITE_OPEN_CREAT:创建数据库。zvfs:要使用vfs模块的名称函数:int 、sqlite3_open(const char *filename, sqlite3 **ppdb);
参数:filename:数据库名,如果为null,则创建一个临时文件,断开后就删除ppdb:SQLite数据库句柄函数:int sqlite_open_v2(const char *filename, sqlite3 **ppdb);
参数:filename:数据库名,如果为null,则创建一个临时文件,断开后就删除ppdb:SQLite数据库句柄

关闭数据库函数:sqlite3_close()

函数:int 、sqlite3_close(sqlite3 *ppdb);
参数:ppdb:SQLite数据库句柄

执行sqlite3_close函数必须要完成与连接关联的所有操作,如果有一个未完成,则返回SQLITE_BUSY。无法关闭连接。

2.执行查询
执行查询函数:sqlite3_exec()

函数:int sqlite3_exec(sqlite3 *ppdb, const char *sql, sqlite_callback, void *data, char **errmsg);
参数:ppdb:打开的数据库sql:sql语句,可以包含多条SQL命令sqlite_callback:回调函数data:回调函数的第一个参数errmsg:指向错误消息字符串的指针,发生错误时,将错误信息写入该字符串中。

demo:

  int main(){sqlite3 *db = NULL;int rc;char *sql = NULL;rc = sqlite3_open("test.db", &db);if (rc != SQLITE_OK) {printf("[%s:%d] open database failed,rc=%d\n", __func__, __LINE__, rc);}sql = "create table stu(id int, name text)";rc = sqlite3_exec(db, sql, NULL, NULL, NULL);if (rc != SQLITE_OK) {printf("[%s:%d] sqlite3 exec:%d\n", __func__, __LINE__, rc);sqlite3_close(db);}sqlite3_close(db);return 0;}

通过参数sqlite_callback和data实现了对sqlite3_exec获得select语句结果的回调机制,回调函数申明如下:

 typedef int (*sqlite3_callback) (void*, int, char**, char**);参数:void*:sqlite3_exec()函数第四个参数提供的数据int:行中字段数目char**:代表行中字段名称的字符串数组char**:代表字段名称的字符串数组返回值:当返回非0的时候,sqlite3_exec()函数就会终止。

3.获取表查询
函数sqlite3_get_table()函数返回一个命令的所有结果集,sqlite3_get_table函数封装了sqlite3_exec函数并尽可能地返回数据,从而更容易获取数据。

函数: int sqlite3_get_table(sqlite3 *db, const char *sql, char ***resultp, int*nrow, int *ncolumn, char **errmsg);
参数:db:数据库句柄sql:SQL语句resultp:用来指向sql执行结果的指针nrow:满足条件的记录的数目(行)ncolumn:每条记录包含的字段数目(列)errmsg:错误信息指针的地址
返回值:成功返回0,失败返回错误码

此函数接收sql命令返回的所有记录,并且存储在 resultp中, resultp使用sqlite3_malloc()申请内存,必须使用sqlite3_free_table()释放内存。

二、准备查询
封装函数将所有步骤封装在一个函数中调用使得某些情况下运行命令会很方便,每个查询函数都提供了自己的行和列的获取方式,但是如果方法封装的越多,那么对执行和结果控制的越少,因此,准备查询提供了更多的功能,更好的控制和更多的信息。

准备查询使用了特殊的函数来访问记录字段和列的信息,列值可以使用函数sqlite3_column_xxx()获取,xxx表示返回值的类型(int、double、blob、char)。因此可以根据自己的需要来检索数据。

在实际应用中,我们通常使用sqlite3_exec()函数对数据库进行修改(创建、丢弃、修改、删除、插入)。而准备查询则用于select语句。因为它提供更多的信息,而且是线性编程,以及使用游标遍历,可以更好地控制结果集。

准备查询执行有三个步骤:编译、执行、完成。使用sqlite3_prepare_v2()或者sqlite3_prepare()函数编译查询,sqlite3_step()函数分布执行查询,使用函数sqlite3_finalize()关闭查询,可以使用sqlite3_reset()函数重用编译。

1.编译
编译或准备SQL语句,并将其编译为虚拟数据库引擎(VDBE)可读的字节码,由函数sqlite3_prepare_v2()或者sqlite3_prepare()完成。

函数:sqlite3_prepare_v2(sqlite3 *db, const char *sql, int nbytes, sqlite3_stmt **ppstmt, const char **pztail)
参数:db:数据库句柄sql:SQL语句文本,UTF-8编码nbytes:sql语句的长度ppstmt:为sqlite3_step()执行的编译好的准备语句的指针pztail:Sql在遇见终止符或者是达到设定的nByte之后结束,假如zSql还有剩余的内容,那么这些剩余的内容被存放到pZTail中,不包括终止符。可以填NULL。

sqlite3_prepare_v2编译sql字符串地第一条SQL语句,分配执行该语句所需的所有资源,并将其字节代码关联到单个语句句柄,由参数ppstmt指定,参数ppstmt是sqlite3_stmt结构体。该数据结构包含了命令的字节码、绑定的参数,B-Tree游标、执行上下文以及sqlite3_step()在执行过程中管理查询状态所需的其他数据。

此函数不会对连接和数据库产生影响,也不会启动事务获取锁,它可以直接通过编译器工作,为执行准备查询。

2.执行
一旦查询语句准备就绪,下一步就是用sqlite3_setp()执行,该函数接收语句句柄并直接与VDBE通信,生成执行SQL语句的字节码指令,第一次调用sqlite3_setp()时候,VDBE获得执行该命令所需的必要的数据库锁,如果不能获得锁,并且木有指派繁忙处理程序,则返回SQLITE_BUSY。如果由则执行繁忙处理程序。

对于不返回数据的SQL语句,sqlite3_setp()第一次调用就执行完SQL语句,并且返回一个指示结果的代码。对于返回数据的SQL语句,例如select语句,sqlite3_setp()第一次调用将语句定位在第一个记录的B-Tree光标上,后续调用sqlite3_setp()将光标定位在结果集内的后续记录。在到达结尾之前,sqlite3_setp()为结果集中的每个记录返回SQLITE_ROW,当到达结尾时候返回SQLIET_DONE。

函数:int sqlite3_setp(sqlite3_stmt *pstmt)
参数:pstmt:qlite3_prepare_v2函数中ppstmt参数指针。

3.完成与重置
一旦语句接收,必须终止,可以使用以下函数之一完成结束或者重置

函数:int sqlite3_finalize(sqlite3_stmt *pstmt);
功能:关闭语句,释放资源并提交或回滚任何隐式事务,清除日志文件并释放相关的锁。
参数:pstmt:qlite3_prepare_v2函数中ppstmt参数指针。函数:int sqlite3_reset(sqlite3_stmt *pstmt);
功能:保持以编辑的SQL语句,但是会将当前语句相关联的变化提交到数据库,如果启动了自动提交,还会释放锁清除日志文件。
参数:pstmt:qlite3_prepare_v2函数中ppstmt参数指针。

二者区别:sqlite3_reset会保留语句关联的资源,使他可以重复执行,避免了再次调用sqlite3_prepare()编译命令。

三、获取记录

除了sqlite3_exec()和sqlite3_get_table()函数获取记录和列之外数据库还提供了其他函数

1.获取字段信息

函数:int sqlite3_column_count(sqlite3_stmt *pstmt);
功能:返回语句句柄关联的字段数,如果不是select语句则返回0.函数:int sqlite3_data_count(sqlite3_stmt *pstmt);
功能:返回当前记录的列数。函数:const char *sqlite3_column_name(sqlite3_stmt*, int icol);
功能:获取当前记录中的所有列
参数:sqlite3_stmt*:语句句柄icol:字段的次序。函数:int sqlite3_column_name(sqlite3_stmt*, int icol);
功能:获取每个字段关联的存储类
参数:sqlite3_stmt*:语句句柄icol:字段的次序。
返回值:1:SQLITE_INTEGER2:SQLITE_FLOAT3:SQLITE_TEXT4:SQLITE_BLOB5:SQLITE_NULL函数:int sqlite3_column_bytes(sqlite3_stmt*, int icol);
功能:获取实际数据长度
参数:sqlite3_stmt*:语句句柄icol:返回信息字段的索引。

2.获取字段值
可以使用sqlite3_column_xxx函数获取当前记录中所有字段值,该函数的通用形式如下:

 xxx sqlite3_column_xxx(sqlite3_stmt*, int icol);

下面是常用的sqlite3_column_xxx()函数:

int sqlite3_column_int(sqlite3_stmt*, int icol);
double sqlite3_column_double(sqlite3_stmt*, int icol);
long long int sqlite3_column_int64(sqlite3_stmt*, int icol);
const void *sqlite3_column_blob(sqlite3_stmt*, int icol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int icol);
const void *sqlite3_column_text16(sqlite3_stmt*, int icol);

3.demo

 int main(){int rc, i, ncols, id, cid;char *name, *sql;sqlite3 *db;sqlite3_stmt *stmt;sql = "select id, name from stu";sqlite3_open("test.db", &db);sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL);ncols = sqlite3_column_count(stmt);rc = sqlite3_setp(stmt);for(i = 0; i < ncols; i++) {printf("column: name = %s\n", sqlite3_column_name(stmt, i));}while(rc == SQLIET_ROW) {id = sqlite3_column_int(stmt, 0);name = sqlite3_column_name(stmt, 1);printf("column: name = %s\n id = %d", name, id);rc = sqlite3_step(stmt);}sqlite3_finalize(stmt);sqlite3_close(db);return 0;}

四、查询参数化

API运行SQL语句中指定参数,为后面参数提供值,绑定的参数与sqlite3_prepare()一起使用。

例子:第一个?可以绑定值2,第二个?绑定字符串“pi”,第三个绑定值3.14

const char *sql = "insert into foo value(?,?,?)";
sqlite3_prepare(db, sql, strlen(sql), &stmt, NULL);
sqlite3_bind_int(stmt, 1, 2);
sqlite3_bind_text(stmt, 2, "pi");
sqlite3_bind_double(stmt, 3, 3.14);
sqlite3_step(stmt);
sqlite3_finalize(stmt);

当sqlite3_prepare()函数识别到SQL语句中有参数时候,在内部为每一个参数分配一个可标识的编号,位置参数从1开始,以此类推顺序整数值。他在生成语句句柄(sqlite3_stmt结构体)中存储这些值。然后期待特定值在执行前绑定到对应参数。

在准备语句之后,可以使用sqlite_bind_xxx()函数绑定参数值

函数:int sqlite3_bind_xxx(sqlite3_stmt*, int i, xxx value);int sqlite3_bind_blob(sqlite3_stmt*, int, const void *, int n, void(*)(void *));
参数:sqlite3_stmt*:语句句柄i: 参数个数value:绑定的值int:次序void *:指向blob数据n:数据的字节长度void(*)(void *)):清理处理程序,一般为NULL

常用绑定函数:

int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int64(sqlite3_stmt*, int, long long int);
int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_blob(sqlite3_stmt*, int, const void *, int n, void(*)(void *));
int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
int sqlite3_bind_text(sqlite3_stmt*, int, const void *, int n, void(*)(void *));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void *, int n, void(*)(void *));

一旦绑定完所有参数,就可以执行sqlite3_step()函数,sqlite3_step()将接收绑定值,替换SQL语句中的对应参数,然后开始执行命令。

参数编号:允许为参数指定编号,而不是必须使用内部的序列,语法是在?后面加一个数字。
例子:

 const char *sql = "insert into foo value(?10,?100,?1000)";sqlite3_prepare(db, sql, strlen(sql), &stmt, NULL);sqlite3_bind_int(stmt, 10, 2);sqlite3_bind_text(stmt, 100, "pi");sqlite3_bind_double(stmt, 1000, 3.14);

四、错误与异常

1.错误处理
可以使用sqlite3_errmsg()获取给定错误的详细信息
函数:const char *sqlite3_errmsg(sqlite3 *);
参数:sqlite3 *:连接句柄
返回值:返回最近连接上API调用产生的错误,如果木有错误则返回 “not an error”

下图是所有SQLite返回的结果

2.繁忙情况处理
有关处理查询的两个重要函数是sqlite3_busy_handler()和sqlite_busy_timeout(),如果所使用的数据库有其他连接的操作,可能会发生冲突,最终需要等待锁返回SQLITE_BUSY。此时需要处理SQLITE_BUSY,每当调用需要锁的SQLite的API函数并且SQLite无法获得锁,函数j就会返回SQLITE_BUSY。处理情况有以下三种:

  • 自己出路SQLITE_BUSY,通过重新运行该语句,或采取一些其他操作

  • 让SQLite调用繁忙处理程序

  • 让SQLite等待一段锁接触的时间。

第三种情况会需要sqlite3_busy_timeout()函数,该函数可以告诉SQLite在返回SQLITE_BUSY前需要等待多长时间锁可以清除。

第二种情况需要使用sqlite3_busy_handler()。该函数提供了调用用户定义函数的方法而不是阻塞等待或返回SQLITE_BUSY.

函数:int sqlite3_busy_handler(sqlite3*, int(*)(void*, int), void*);
参数:sqlite3 *:连接句柄int(*)(void*, int):指向繁忙处理程序的函数指针void*:指向应用程序特定数据的指针,作为繁忙处理程序的第一个参数。
注意:在繁忙处理程序中关闭数据库会导致数据库崩溃。

3.模式改变处理
当连接更改了数据库模式,所有在改变发生前编译的准备语句都会失效。这些语句在第一个sqlite_step()调用将尝试重新编译有关SQL并尽可能正常进行,如果重新编译无法实现,则函数sqlite_step()返回SQLITE_SCHEMA。这种情况就是处理改变并重新开始。以下情况下会导致SQLITE_SCHEMA错误

  • 分离数据库

  • 修改或安装用户自定义的函数或聚合

  • 修改或安装用户自定义的排序规则

  • 修改或安装授权函数

  • 清理数据库k空间

QLITE_SCHEMA错误的最终原因是与VDBE有关,当连接更改模式时,其他已编译查询的VDBE代码可能会指向一个不存在或数据库位置已经改变的对象。为了避免产生错误,SQLite将已编译但未执行的所有语句无效化。他们必须重新编译。

五、控制操作

API提供了一些函数,可以在编译时和运行时监视和管理SQL命令,这些函数可以安装用来监视数据库的回调函数,通常在各种数据库事件发生时控制这些事件。

1.提交钩子

函数:void *sqlite3_commit_hook(sqlite3 *cnx, int(&xcallback)(void *data), void *data);
功能:监视给定连接上的事务提交事件
参数:cnx:数据库句柄,当连接cnx上提交事务时将触发xcallback回调函数。int(&xcallback)(void *data):回调函数,如果回调函数返回值非0,提交将转换为回滚。如果回调函数中指针传入NULL,则可以禁止当前注册函数。data:应用程序数据,传递给回调函数的参数。
返回值:在给定连接一次只能注册一个回调函数,如果之前没有注册过sqlite3_commit_hook则返回NULL,如果之前注册过则返回以前的参数data值。

2.回滚钩子

函数:void *sqlite3_rollback_hook(sqlite3 *cnx, void(&xcallback)(void *data), void *data);
功能:给定连接上的回滚事件。注册回调函数xcallback,连接cnx上的回滚事件触发回调函数,不管是通过显示的回滚命令、隐式错误还是为犯错误导致的回滚。如果是因为数据库关闭连接导致的回滚则无法触发回调函数。
参数:cnx:数据库句柄,当连接cnx上提交事务时将触发xcallback回调函数。void(&xcallback)(void *data):回调函数。data:应用程序数据,传递给回调函数的参数。

3.更新钩子

函数:void *sqlite3_update_hook(sqlite3 *cnx, void(*)(void *, int, char const*, char const*, sqlite_int64), void *data);
功能:用于监视给定连接上对行的所有更新、插入和删除操作。
参数:cnx:数据库句柄回调函数具体形式:void callback(void *data, int operation_code, char const *db_name, char const *table_name, sqlite3_int64 rowid);参数:data:指向特定应用程序的数据指针。由sqlite3_update_hook函数第三个参数data提供。operation_code:SQLITE_INSERT:插入操作SQLITE_UPDATE:更新操作SQLITE_DELETE:删除操作db_name:对应数据库名称table_name:操作发生表的名称rowid:受影响的行
返回值:如果之前存在回调函数,返回值是指向之前回调函数数据的指针。

4.授权函数

函数:int sqlite3_set_authorizer(sqlite3*, int(*xAuth)(void*, int, const char*, const char*, const char*, const char*), void *puserdata);
功能:监控或控制查询语句的编译,最强大的事件过滤器
参数:回调函数:SQLite在语句编译时为各种数据库事件调用回调函数,使程序可以安全地执行用户提供的SQL, 它提供了一种限制某种SQL操作或否定对数据库中特定表或字段的访问方法。int auth(void*,       //用户数据,sqlite3_set_authorizer函数第四个参数提供int,           //事件代码  授予什么类型的操作权限const char*, //事件具体相关的参数const char*, //事件具体相关的参数const char*, //数据库名称const char*);    //触发器或视图名称,如果为NULL。直接访问SQL语句。

六、线程

SQLite3是支持多线程的,但是不允许fork()调用将连接传递给子进程,否则无法工作。

1.共享缓存模型
SQLite3支持共享缓存模式,如下图,允许一个进程中多个连接使用共同的页缓存,该功能使用单个线程能够代表其他线程有效管理多个数据库连接的嵌入式服务器。这种情况下,连接共享单个页缓存以及不同的并发模型,与单个线程管理自己的连接相比较,共享缓存使服务器大大减内存的使用。通常情况下共享缓存模式与其他线程共享一个页缓存,不必每个线程都消耗那么多缓存。
下图共享缓存模式

共享缓存模式中,线程依赖于服务器线程帮助他们管理数据库连接。线程通过一种通信机制来向服务器发生SQL语句,服务器使用线程分配的连接执行他们,然后返回结果。线程可以继续发生命令并且控制自己的事务,实际连接存在于主线程由其管理。

默认情况下,共享缓存模式使用表锁分别保持读连接和写连接,表锁和数据库锁不同,他们在共享缓存下的连接中存在,当连接读表时,SQLite试图获取表上的读锁定,写表也是如此,连接不可以向另一个已经有读锁定的连接表写入。表锁绑定到各自的连接并且只在其事务内有效。

SQLite3中核心C API相关推荐

  1. sqlite java blob_【转】好东西!sqlite3中BLOB数据类型存储大对象运用示例

    1:常用接口 个人比较喜欢sqlite, 使用最方便,唯一的准备工作是下载250K的源:而且作者很热心,有问必答. 以下演示一下使用sqlite的步骤,先创建一个数据库,然后查询其中的内容.2个重要结 ...

  2. 使用Http-Repl工具测试ASP.NET Core 2.2中的Web Api项目

    今天,Visual Studio中没有内置工具来测试WEB API.使用浏览器,只能测试http GET请求.您需要使用Postman,SoapUI,Fiddler或Swagger等第三方工具来执行W ...

  3. 在ASP.NET Core 2.0中创建Web API

    目录 介绍 先决条件 软件 技能 使用代码 第01步 - 创建项目 第02步 - 安装Nuget包 步骤03 - 添加模型 步骤04 - 添加控制器 步骤05 - 设置依赖注入 步骤06 - 运行We ...

  4. hibernate框架(二)核心配置API

    一:核心配置分为三大部分  必须的配置 .可选的配置和引入映射文件. 1.必须的配置 连接数据库的参数:驱动类  url路径  用户名  密码  方言 <property name=" ...

  5. python flink_如何在 Apache Flink 中使用 Python API?

    原标题:如何在 Apache Flink 中使用 Python API? 导读:本文重点为大家介绍 Flink Python API 的现状及未来规划,主要内容包括:Apache Flink Pyth ...

  6. java加密与解密-核心包中的部分API(2)

    主要是介绍java安全框架的核心包中的部分API作用 java.Security包 ​ java.security包主要用于为安全框架提供类和接口 Provider类 Provider类实现了java ...

  7. Windows核心编程 - API HOOK应用

    #Windows核心编程 - API HOOK应用 如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033 目录 文章目录 #Windows核 ...

  8. 13个Vue3中的全局API的源码浅析汇总整理

    前言 不知不觉vue-next的版本已经来到了3.1.2,最近对照着源码学习vue3的全局Api,边学习边整理了下来,希望可以和大家一起进步. 我们以官方定义.用法.源码浅析三个维度来一起看看它们.下 ...

  9. 【java中常用的API】

    java中有很多常用的API,它们提供了便捷的使用方法和工具类,让我们来看一看java中常用的API吧. 1.math类: 它包含基本的数字运算方法,如对数.指数.平方根和三角函数等,一般数据类型为d ...

最新文章

  1. Docker 之 Dockerfile 的概述与使用
  2. windows powershell实战指南_【安全研究】powershell在主机中是否存在安全隐患?
  3. 怎样写出可维护的面向对象javascript(译)
  4. 安装 | Android studio连接不上真机解决办法(电脑安装虚拟机不成功的情况下)
  5. 调用startActivityForResult后,onActivityResult无响应的题目
  6. P1341 无序字母对
  7. python正则表达式数字开头_Python正则表达式总结
  8. 类和对象编程(二):类访问修饰符
  9. JDBC03 Statement接口
  10. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-3.微信Oauth2.0交互流程讲解...
  11. HTML5九宫格拼图小游戏
  12. c++字符串逆序输出
  13. C++ endian转换
  14. 注销手机号,存在重大安全问题
  15. 深信服2019秋招技服岗面试总结
  16. 字节跳动后端面经(17)
  17. 存在外键关联的主表truncate如何做
  18. 秋招冲刺:网络安全工程师入围成功之旅!!
  19. OSChina 周一乱弹 —— 装睡看看男友的反应
  20. verilog实现I2C控制器 (小梅哥思路)----详细解析

热门文章

  1. Linux下Node.js安装及环境配置
  2. linux 套接口文件_继上一篇,继续介绍linux 套接口
  3. 服务器低功耗cpu性能,节能省电家庭共享 7款低功耗处理器推荐
  4. abb机器人焊接编程视频教程_智能制造仿真编程之带导轨的ABB机器人
  5. python参数类型定义_Python的参数类型
  6. 【电脑帮助】解决Wind10系统每次运行软件时都要出现提示框的问题
  7. mysql防止误操作之prompt命令提示符
  8. nginx ---- nginx.conf核心配置文件
  9. IPLAT62--后台返回提示参数
  10. android java调用c_Android JNI简单实例(android 调用C/C++代码)