SQLite核心源代码由C语言写就,同时提供了很多的扩展包可应用于其他编程语言和类库,如Python、Ruby、Java、Perl、.Net/C#、Qt和ODBC。在很多情况下,针对一种语言有很多扩展包可供选择,诸多的扩展包为不同的程序员满足不同的需求而设计开发。

由于笔者目前从事嵌入式开发相关的工作,所以从C语言的角度对SQLite的api进行探索和实践,本文主要从实例出发,结合代码在实践中学习与理解C API的使用,关于C/C++ 接口函数更细节的部分本文不再详细赘述,请具体请参考官方文件 An Introduction To The SQLite C/C++ Interface或者《SQLite 权威指南》。

C/C++ 接口函数概述

数据库连接对象和SQL语句对象由下面几个核心的C/C++接口来控制:sqlite3_open()、sqlite3_prepare()、sqlite3_step()、sqlite3_column()、sqlite3_finalize()、sqlite3_close()。

使用SQLite3时根据以上函数大概分为几个过程,这几个过程是概念上的说法,而不完全是程序运行的过程,如sqlite3_column()表示的是对查询获得一行里面的数据的列的各个操作统称,实际上在sqlite中并不存在这个函数。在SQLite提供的C/C++接口中,其中5个API属于核心接口。相比于其它数据库引擎提供的API,如OCI、MySQL API等,SQLite提供的接口易于理解和掌握。

以上六个C/C++接口及上面的两个对象构成SQLite的核心功能。注意这些接口有些有多个版本,例如sqlite3_open()有三个独立的版本:sqlite3_open(), sqlite3_open16()和sqlite3_open_v2(),它们以稍微不同的方式完成同样的事情。sqlite3_column()代表一个家族系列:sqlite_column_int(), sqlite_column_blob()等等,用于提取结果集中各种类型的列数据。

一个SQL数据库引擎的首要任务是执行SQL语句以获得我们想要的数据。为了完成这个任务,开发需要知道两个对象数据库连接对象sqlite3和SQL预处理语句对象sqlite3_stmt,定义如下:

    typedef struct sqlite3 sqlite3;
     typedef struct sqlite3_stmt sqlite3_stmt;

严格地说,SQL预处理语句对象不是必需的,因为有使用方便的包装函数sqlite3_exec或sqlite3_get_table,它们封装并且隐藏了SQL语句对象。不过理解SQL语句对象能更好地使用SQLite。

代码实践

以下为具体的实践代码,相关总结与心得以注释的形式插入在代码,在执行代码前,请先下载SQLite源码并存储在同一路径下,按照以下方式执行编译即可:(也可将sqlite3编译成函数库再调用,具体请参照笔者另一篇文章sqlite 安装与编译)

gcc sqlite3.c test_api.c -lpthread -ldl -o testapi -I.

具体实践代码如下:

 #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sqlite3.h> int main( int argc, char **argv )
{
sqlite3 *db;
sqlite3_stmt * stmt;
const char *zTail;
int rc = -;
char *sql; /*1. 连接数据库*/
/*int sqlite3_open(
*const char *filename, // 数据库文件名 (UTF-8)
*sqlite3 **ppDb, // OUT: SQLite数据库句柄
*int flags, // 数据库文件操作标志
*const char *zVfs // 用于重写默认操作系统接口sqlite3_vfs的方法
*);
*/
rc = sqlite3_open_v2("mysqlite.db", &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
if(rc != SQLITE_OK){
printf("%s\n", sqlite3_errmsg(db));
} /*2. 创建Table*/
/*sqlite3_prepare_v2()将SQL语句编译为sqlite内部一个结构体(sqlite3_stmt),
*该结构体中包含了将要执行的SQL语句的信息
*第四个参数用来指向输入参数中下一个需要编译的SQL语句存的 SQLite statement 对象的指针
*注意现在sqlite3_prepare()已经不被推荐使用了,目前官司方推荐使用sqlite3_prepare_v2()
*SQLITE_API int sqlite3_prepare_v2(
*sqlite3 *db, // SQLite数据库句柄
*const char *zSql, // SQL 语句, UTF-8 编码
*int nByte, // zSql的字节长度
*sqlite3_stmt **ppStmt, // OUT: sql语句句柄(statement handle)
*const char **pzTail // OUT: 指向zSql未使用的部分
*);
*/
sql = "CREATE TABLE players ( \n\
id INTEGER PRIMARY KEY, \n\
name TEXT, \n\
age INTEGER);";
rc = sqlite3_prepare_v2(db, sql, -, &stmt, &zTail);
if(rc != SQLITE_OK){
printf("%s\n", sqlite3_errmsg(db));
} /*调用sqlite3_step(),此时SQL语句才真正执行,执行成功,返回SQLITE_DONE或SQLITE_ROW.
*每次调用sqlite3_step(),只返回一行数据,使用sqlite3_column_XXX()函数来取出这些数据
*要取出全部的数据,则需要反复调用sqlite3_step()
*/
rc = sqlite3_step(stmt);
if(rc != SQLITE_DONE){
printf("%s\n", sqlite3_errmsg(db));
} /*调用sqlite3_finalize(),释放stmt占用的内存,该内存是在sqlite3_prepare()时分配的
*如果SQL语句要重复使用,可以调用sqlite3_reset()来清除已经绑定的参数
*/
rc = sqlite3_finalize(stmt);
if(rc != SQLITE_OK){
printf("%s\n", sqlite3_errmsg(db));
} /*3.1 插入数据*/
sql = "INSERT INTO players (name,age) VALUES(?,?);";
rc = sqlite3_prepare_v2(db, sql, -, &stmt, &zTail);
if(rc != SQLITE_OK){
printf("%s\n", sqlite3_errmsg(db));
} /*sqlite3_bind_xxx的第四个参数为负,则字符串长度由第一个0终的位数决定
*SQLITE_STATIC表示命令执行完后的信息为static类型,不能被改动,而且不需要被free
*/
char str[] = "Kevin";
int n = ;
sqlite3_bind_text(stmt,,str,-,SQLITE_STATIC);
sqlite3_bind_int(stmt,,n);
rc = sqlite3_step(stmt);
if( rc != SQLITE_DONE){
printf("%s",sqlite3_errmsg(db));
} //清除已经绑定的参数
sqlite3_reset(stmt);
//插入第二个数据
char str2[] = "Jack";
int n2 = ;
sqlite3_bind_text(stmt,,str2,-,SQLITE_STATIC);
sqlite3_bind_int(stmt,,n2);
rc = sqlite3_step(stmt);
if( rc != SQLITE_DONE){
printf("%s",sqlite3_errmsg(db));
}
sqlite3_finalize(stmt); //释放stmt所占的内存 /*3.2 插入数据*/
char **pz_err_msg = NULL;
sql = "INSERT INTO players(name, age) VALUES('Rose', 24);";
rc = sqlite3_exec(db, sql, NULL, NULL, pz_err_msg);
if (SQLITE_OK != rc) {
printf("%s:sqlite3_exec insert \"%s\" failed\n", __FUNCTION__, sql);
if (NULL != pz_err_msg) {
printf("%s: error: %s\n", __FUNCTION__, *pz_err_msg);
sqlite3_free(pz_err_msg);
pz_err_msg = NULL;
}
} /*4. 查询所有数据*/
sql = "SELECT id, name, age FROM players ORDER BY age";
rc = sqlite3_prepare_v2(db, sql, -, &stmt, &zTail);
if(rc != SQLITE_OK){
printf("%s\n", sqlite3_errmsg(db));
} int number, id;
const unsigned char * name;
/*
** 执行SQL语句之后会,sqlite3_step()会返回不同的参数,如[SQLITE_BUSY],[SQLITE_DONE],
** [SQLITE_ROW], [SQLITE_ERROR], [SQLITE_MISUSE].
** 当该函数完成一次类似查询(select)的SQL语句执行后,将返回[SQLITE_ROW],每执行一次
** sqlite3_step(),都将准备好一行新的查询数据结果,该结果可通过sqlite3_column()系列函
** 数获取;要查询下一行的数据,只需重复执行sqlite3_step()即可。
*/
rc = sqlite3_step(stmt);
while( rc == SQLITE_ROW ){
id = sqlite3_column_int( stmt, ); //该函数用于获取当前行指定列(id)的数据(int类型)
name = sqlite3_column_text( stmt, );
number = sqlite3_column_int( stmt, );
printf("ID: %d Name: %s Age: %d \n",id,name,number);
sleep();
rc = sqlite3_step(stmt);
}
rc = sqlite3_finalize(stmt);
if(rc != SQLITE_OK){
printf("%s\n", sqlite3_errmsg(db));
} /*5. 删除数据*/
sql = "DELETE FROM players WHERE age < 24;";
rc = sqlite3_exec(db, sql, NULL, NULL, pz_err_msg);
if (SQLITE_OK != rc) {
printf("%s:sqlite3_exec insert \"%s\" failed\n", __FUNCTION__, sql);
if (NULL != pz_err_msg) {
printf("%s: error: %s\n", __FUNCTION__, *pz_err_msg);
sqlite3_free(pz_err_msg);
pz_err_msg = NULL;
}
} /*6. 查询所有数据2*/
int nrow = , ncol = ;
int i, j;
char **result;
sql = "SELECT id, age, name FROM players;";
rc = sqlite3_get_table(db, sql, &result, &nrow, &ncol, pz_err_msg);
if (SQLITE_OK != rc)
{
printf("%s:sqlite3_get_table \"%s\" failed\n", __FUNCTION__, sql);
if (NULL != pz_err_msg)
{
printf("%s: error: %s\n", __FUNCTION__, *pz_err_msg);
sqlite3_free(pz_err_msg);
pz_err_msg = NULL;
}
}
for(i=; i < nrow+; i++) {
for(j=; j < ncol; j++) {
printf("%s ", result[i * ncol + j]);
}
printf("\n");
} /*5. 关闭数据库*/
sqlite3_close(db);
return ;
}

SQLite接口函数 - C核心api实践与总结的更多相关文章

  1. Linux时间子系统之(三):用户空间接口函数

    专题文档汇总目录 Notes:用户空间时间相关接口函数: 类型 API 精度 说明 时间 time stime time_t 精度为秒级 逐渐要被淘汰.需要定义__ARCH_WANT_SYS_TIME ...

  2. SQLite使用(三)&&核心API使用

    概述     SQLite提供了一系列接口供用户访问数据库,主要包括连接数据库,处理SQL,迭代查询结果等.本文会针对我们使用SQLite的主要场景,列出核心的API,详细介绍API的用法并给出代码用 ...

  3. 使用line_profiler查看api接口函数每行代码执行时间

    项目情景描述: 在restful架构风格的项目交付测试的过程中,某接口出现 请求超时导致的http 502 Bad Gateway,于是开始排查具体是接口函数中的哪行代码或函数 响应时间过长导致的50 ...

  4. 【核心API开发】Spark入门教程[3]

    本教程源于2016年3月出版书籍<Spark原理.机制及应用> ,在此以知识共享为初衷公开部分内容,如有兴趣,请支持正版书籍. Spark综合了前人分布式数据处理架构和语言的优缺点,使用简 ...

  5. spark 入门学习 核心api

    spark入门教程(3)--Spark 核心API开发 原创 2016年04月13日 20:52:28 标签: spark / 分布式 / 大数据 / 教程 / 应用 4999 本教程源于2016年3 ...

  6. SQLite3开发接口函数详解

    SQLite3是SQLite一个全新的版本,它虽然是在SQLite 2.8.13的代码基础之上开发的,但是使用了和之前的版本不兼容的数据库格式和API. SQLite3是为了满足以下的需求而开发的: ...

  7. java多线程核心api以及相关概念(一)

    这篇博客总结了对线程核心api以及相关概念的学习,黑体字可以理解为重点,其他的都是我对它的理解 个人认为这些是学习java多线程的基础,不理解熟悉这些,后面的也不可能学好滴 目录 1.什么是线程以及优 ...

  8. ASP.NET Web API实践系列04,通过Route等特性设置路由

    ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程.在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一 ...

  9. hibernate系列笔记(2)---Hibernate的核心API

    Hibernate的核心API 一般我们通过hibernate进行操作的时候,都会遵循下面的流程,那么接下来我对每一个步骤进行讲解: 1 public void testInsert() { 2 // ...

随机推荐

  1. linux高性能服务器编程 (九) --I/O复用

    第九章 I/O复用 I/O复用就是一个线程可以同时监听多个文件描述符,提高程序性能.虽然I/O复用可以同时监听多个文件描述符,但是它本身是阻塞的,如果多个文件描述符准备就绪,如果不采取措施它仍然是串行 ...

  2. Xcode9/iOS 11 无线调试方法

    1.确保手机已经升级到 iOS 11 ,Xcode 已经升级到 9.0 版本,用手机连接电脑,打开 Xcode 选择路径如下图 2.勾选 Connect via network ,勾选之后拔掉手机. ...

  3. 记一次cpu指标异常的跟踪排查

    问题描述: 最近在测试环境的服务器上,无意中发现cpu持续飙高.最高的时候达到了200%经过反复重启无效之后,决定挖掘深层次的原因 通过top命令打印出消耗cpu的pid,如图 通过ps -mp 24 ...

  4. Mac版最详细的Flutter开发环境搭建

    上周任务不多,闲来无事想学习一下flutter耍一耍,发现flutter的环境搭建步骤还是很繁琐的,官网的搭建教程只是按步骤让你进行操作,中间出现的问题完全没有提及,对我这种没搞过原生开发的小白来说超 ...

  5. Video标签动态修改src地址播放问题

    不管在React或Vue中,将一个变量赋值给src属性,当修改这个变量的值时,video播放的还是原来的视频. Vue中 <video id="root"> <s ...

  6. CSRF的防御

    声明 本文转自:跨站请求伪造漏洞

  7. 微信小程序支付接口之Django后台

    本文链接:https://blog.csdn.net/qq_41860162/article/details/89098694Python3-django-微信小程序支付接口调用工具类生成一系列微信官 ...

  8. linux查找历史命令

    1.ctr+r  输入搜索关键词 2.&history 3.上箭头翻看

  9. 009 webpack将ES高级语法进行装换

    一:ES高级转换 1.main.js中的js不能解析 // js的主要入口 import $ from 'jquery' import './css/index.css' import './css/ ...

  10. C# Mysql 查询 Rownum

    SELECT @rownum:=@rownum+1 AS rownum,a.order_id ,case when a.Ordered =1 then '已分单' end as Ordered,a.p ...