SQLite接口函数 - C核心api实践与总结
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实践与总结的更多相关文章
- Linux时间子系统之(三):用户空间接口函数
专题文档汇总目录 Notes:用户空间时间相关接口函数: 类型 API 精度 说明 时间 time stime time_t 精度为秒级 逐渐要被淘汰.需要定义__ARCH_WANT_SYS_TIME ...
- SQLite使用(三)&&核心API使用
概述 SQLite提供了一系列接口供用户访问数据库,主要包括连接数据库,处理SQL,迭代查询结果等.本文会针对我们使用SQLite的主要场景,列出核心的API,详细介绍API的用法并给出代码用 ...
- 使用line_profiler查看api接口函数每行代码执行时间
项目情景描述: 在restful架构风格的项目交付测试的过程中,某接口出现 请求超时导致的http 502 Bad Gateway,于是开始排查具体是接口函数中的哪行代码或函数 响应时间过长导致的50 ...
- 【核心API开发】Spark入门教程[3]
本教程源于2016年3月出版书籍<Spark原理.机制及应用> ,在此以知识共享为初衷公开部分内容,如有兴趣,请支持正版书籍. Spark综合了前人分布式数据处理架构和语言的优缺点,使用简 ...
- spark 入门学习 核心api
spark入门教程(3)--Spark 核心API开发 原创 2016年04月13日 20:52:28 标签: spark / 分布式 / 大数据 / 教程 / 应用 4999 本教程源于2016年3 ...
- SQLite3开发接口函数详解
SQLite3是SQLite一个全新的版本,它虽然是在SQLite 2.8.13的代码基础之上开发的,但是使用了和之前的版本不兼容的数据库格式和API. SQLite3是为了满足以下的需求而开发的: ...
- java多线程核心api以及相关概念(一)
这篇博客总结了对线程核心api以及相关概念的学习,黑体字可以理解为重点,其他的都是我对它的理解 个人认为这些是学习java多线程的基础,不理解熟悉这些,后面的也不可能学好滴 目录 1.什么是线程以及优 ...
- ASP.NET Web API实践系列04,通过Route等特性设置路由
ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程.在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一 ...
- hibernate系列笔记(2)---Hibernate的核心API
Hibernate的核心API 一般我们通过hibernate进行操作的时候,都会遵循下面的流程,那么接下来我对每一个步骤进行讲解: 1 public void testInsert() { 2 // ...
随机推荐
- 鸿蒙OS还有机会吗?
鸿蒙最初的定位是手机操作系统,那在市场已饱和.生态已成熟,Android地位已牢不可破的当下,能成功是小概率事件,就像PC时代无法撼动Windows地位一样. 好在鸿蒙调整定位定义为面向未来的IOT操 ...
- CTSC 2017 游戏[概率dp 线段树]
小 R 和室友小 B 在寝室里玩游戏.他们一共玩了 $n$ 局游戏,每局游戏的结果要么是小 R 获胜,要么是小 B 获胜. 第 $1$ 局游戏小 R 获胜的概率是 $p_1$,小 B 获胜的概率是 $ ...
- 小说美句摘抄&&动漫壁纸
不知道为啥脑子一抽打算开个坑(反正咱是个不务正业的人) 大部分是网文里的,某些是轻小说里的,文学名著--咱也不像会看那个的人啊-- upd 2019.11.6:把一些自己觉得好的动漫壁纸贴一贴,图床用 ...
- ring3 x32挂起进程注入原理.
目录 一丶挂起进程注入简介与前言 二丶ShellCode核心讲解. 2.1 保存Contex.EIP 2.2 DLL路径重定位 2.3 LoadLibrary的重定位 三丶 全部C++代码.拷贝即可使 ...
- MYSQL避免重复插入记录的三种方法
方案一:使用ignore关键字 如果是用主键primary或者唯一索引unique区分了记录的唯一性,避免重复插入记录可以使用: insert ignore into table_name(ema ...
- 数据结构Java版之基数排序(四)
基数排序: 基数排序分为两种:第一种是LSD ,从最低位开始排序, 第二种是 MSD 从最高位开始排.这里介绍第一种LSD排序算法. 首先,我们先了解什么是基数.基数是根据具体的排序情况而定的,比如我 ...
- java基础之 clone
参考文档:深拷贝&浅拷贝:http://blog.csdn.net/cws1214/article/details/52193341 克隆的分类: (1)浅克隆(shallow clone) ...
- Python中如何计算字符串里面某一个字符出现的次数?
一个突发奇想,想解决一个学习中的行业痛点,让我又再度拾起了Python编程语言的学习. 刚学两天,今天遇到一个题,该题难度不高,但有一点关键点在网上找不到,网上也没有相关的答案,于是我只好千辛万苦 ...
- Mockito 的用法
本文为博主原创,转载请注明出处: Mockito 是一个基于MIT协议的开源java测试框架. Mockito区别于其他模拟框架的地方主要是允许开发者在没有建立“预期”时验证被测系统的行为.对于moc ...
- Linux 磁盘管理_016
以5个方面讲解 1. 硬盘 2. 磁盘RAID.LVM等 3. 磁盘分区 4. 磁盘格式化 5. 磁盘挂载后磁盘管理 一.硬盘 硬盘分类 备注 机械硬盘 IDE SCSI SATA SAS 固态 ...