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. P1005 矩阵取数

    题目链接 看完题可能第一时间并没有清晰的思路.让我们一步一步的来考虑这道题目. 题目中描述操作为每次从所有的行中选取,这样做有些麻烦.仔细思考一下可以发现行与行之间互不干涉,所以我们可以对每行操作到底 ...

  2. 【NOI2002】荒岛野人(信息学奥赛一本通 1637)(洛谷 2421)

    题目描述 克里特岛以野人群居而著称.岛上有排列成环行的M个山洞.这些山洞顺时针编号为1,2,…,M.岛上住着N个野人,一开始依次住在山洞C1,C2,…,CN中,以后每年,第i个野人会沿顺时针向前走Pi ...

  3. 织梦一二级导航菜单被点击顶级栏目高亮(加class)解决方法

    织梦一二级导航菜单被点击的栏目高亮显示方法详解,废话不多说直接举例说明: 织梦一级菜单被点击栏目高亮调用方法: {dede:channel typeid ='1'  type ='son' curre ...

  4. fluent在运行时改变重力方向方法总结

    Fluent版本:19.0(其他版本应该也适用) 这里我们用一个简单的算例(同心环中的自然对流)来说明 算例来自<ANSYS Fluid Dynamics Verification Manual ...

  5. Python并发请求之requests_future模块使用

    # -*- coding: utf-8 -*- # @Time : 2019-12-09 10:00 # @Author : cxa # @File : demo.py # @Software: Py ...

  6. Spring Transaction 使用入门

    一.开篇陈述 1.1 写文缘由 最近在系统学习spring框架IoC.AOP.Transaction相关的知识点,准备写三篇随笔记录学习过程中的感悟.这是第一篇,记录spring Transactio ...

  7. CAP原则 (阿里)

    CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency).可用性(Availability).分区容错性(Partition tolerance).CAP 原则指的是,这三 ...

  8. leetcode:146. LRU缓存机制

    题目描述: 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 ( ...

  9. nginx 日志打印响应时间 request_time 和 upstream_response_time

    设置log_format,添加request_time,$upstream_response_time,位置随意 og_format  main  '"$request_time" ...

  10. Android Sensor详解(1)简介与架构【转】

    本文转载自:https://blog.csdn.net/u013983194/article/details/53244686 最近在学习有关如何porting sensor的东西,仅借此机会写博客来 ...