Linux平台上SQLite数据库教程(二)——C语言API介绍
来源:互联网 发布:java gbk utf8 转换 编辑:程序博客网 时间:2024/06/07 06:51
Linux平台上SQLite数据库教程(二)——C语言API介绍
前言:本文将介绍几个基本的SQLite3数据库的C语言API接口,主要用到两个文件:sqlite3.c、sqlite3.h。源码地址:https://github.com/AnSwErYWJ/SQLite。
打开数据库
1.原型:
int sqlite3_open( const char* filename, /* 数据库文件名, 必须为 UTF-8 格式 */ sqlite3** ppDB /* 输出: SQLite 数据库句柄 */);;
2.说明:
参数filename为指定打开的数据库, sqlite3的结构指针 *ppDB 为数据库连接句柄。如果数据库被成功打开(和/或 创建), 函数返回 SQLITE_OK;否则返回一个错误码, 可以通过* sqlite3_errmsg()* 查看错误原因.。出错,则只可能是 SQLite 无法为 SQLite 对象分配内存空间, 此时将返回 NULL。
关闭数据库
1.原型:
int sqlite3_close( sqlite3* pDB /* 由 sqlite3_open 或基相关的函数打开的 SQLite 对象句柄 */ );
2.说明:
该函数用来关闭 sqlite3 对象。返回 SQLITE_OK 表示对象被成功关闭,以及所有相关的资源被成功回收。应用程序必须在关闭之前 “完成(finalize)” 所有的 “预编译语句(prepared statements)”, 并且关闭所有的 “二进制句柄绑定(BLOB handle)”, 如果在关闭时还有未完成的预编译语句或二进制句柄, 那么函数返回 SQLITE_BUSY(5)。
错误处理
原型1:
const char *sqlite3_errmsg( sqlite3* pDB /* SQLite3 数据库句柄 */);
说明1:
该函数返回与pDB数据库指针相关的错误信息,下次调用会覆盖。
原型2:
int sqlite3_errcode( sqlite3* pDB /* SQLite3 数据库句柄 */)
说明2:
该函数返回最近一次调用 sqlite3_ API时产生的错误码。
示例一:
/************************************************************************* > File Name: example1.c > Author: AnSwEr > Mail: 1045837697@qq.com > Created Time: 2015年08月29日 星期六 14时17分21秒 ************************************************************************/#include<stdio.h>#include<stdlib.h>#include"sqlite3.h"int main(void){ char *filename = "./first.db"; sqlite3 *pDB = NULL; int ret = 0; ret = sqlite3_open(filename,&pDB); if(ret != SQLITE_OK) { fprintf(stderr,"%s\n",sqlite3_errmsg(pDB)); exit(EXIT_FAILURE); } /*do something*/ printf("open successfully!\n"); if(pDB != NULL) { sqlite3_close(pDB); pDB = NULL; } printf("close successfully!\n"); return 0;}
示例一实现打开和关闭操作。
执行sql语句
原型:
int sqlite3_exec( sqlite3* pDB, /* sqlite3句柄 */ const char* sql, /* 被执行的 SQL 语句 */ int (*callback)(void*,int,char**,char**), /* 执行/查询回调函数 */ void* pvoid, /* 传递给回调函数的第一个参数 */ char**errmsg /* 错误输出信息 */);
说明:
当回调函数不为 NULL, 则它对每一个行查询结果都会调用该回调函数;如果没有回调函数被指定, sqlite3_exec() 只是简单地忽略查询结果。
如果回调函数返回非零,sqlite3_exec() 立即中断查询,并且不再执行后续的 SQL 语句,也不再调用回调函数, sqlite3_exec() 将返回 SQLITE_ABORT 结束执行。
当发生错误时, 执行将中断。如果 errmsg 参数不为空,错误信息将会被写入(errmsg 由 sqlite3_malloc() 分配内存空间,由sqlite3_free() 释放该内存空间)。如果 errmsg 参数不为 NULL, 并且没有错误发生, errmsg 被设置为 NULL。
通常情况下callback在select操作中会使用到,如果不需要回调函数。第三第四个参数设为NULL。
回调函数原型:
int callback( void *params, /*params是sqlite3_exec传入的第四个参数*/ int column_size, /*column_size是结果字段的个数*/ char **column_value, /*column_value是返回记录的一位字符数组指针*/ char **column_name /*column_name是结果字段的名称*/);
示例二
/************************************************************************* > File Name: example2.c > Author: AnSwEr > Mail: 1045837697@qq.com > Created Time: 2015年08月29日 星期六 20时11分06秒 ************************************************************************//* * 查询数据库 */#include<stdio.h>#include<stdlib.h>#include"sqlite3.h"static print_info(void *params,int column_size,char **column_value,char **column_name){ int i; for(i=0;i<column_size;i++) printf("\t%s",column_value[i]); printf("\n"); return 0;}int main(void){ char *filename = "./first.db"; sqlite3 *pDB = NULL; int ret = 0; /*open*/ ret = sqlite3_open(filename,&pDB); if(ret != SQLITE_OK) { fprintf(stderr,"%s\n",sqlite3_errmsg(pDB)); exit(EXIT_FAILURE); } /*select*/ char *errmsg = 0; ret = sqlite3_exec(pDB,"select * from stutable",print_info,NULL,&errmsg); if(ret != SQLITE_OK) fprintf(stderr,"select error:%s\n",errmsg); sqlite3_free(errmsg); /*close*/ if(pDB != NULL) { sqlite3_close(pDB); pDB = NULL; } return 0;}
示例二执行使用回调函数的select语句。此外,还有不使用回调函数的select语句(使用sqlite3_get_table,此函数是sqlite3_exec的包装)。 不过个人感觉还是使用回调函数好,这样代码可看性强,更整洁。
sqlite3_get_table原型:
int sqlite3_get_table( sqlite3 *db, /* An open database */ const char *zSql, /* SQL to be evaluated */ char ***pazResult, /* Results of the query */ int *pnRow, /* Number of result rows written here */ int *pnColumn, /* Number of result columns written here */ char **pzErrmsg /* Error msg written here */);void sqlite3_free_table(char **result);/*db是sqlite3的句柄zSql是要执行的sql语句pazResult是执行查询操作的返回结果集pnRow是记录的行数pnColumn是记录的字段个数pzErrmsg是错误信息pazResult是一个(pnRow+1)*pnColumn结果集的字符串数组,其中前pnColumn个结果是字段的名称,后pnRow行记录是真实的字段值,如果某个字段为空,则对应值为NULL。
这里贴一段网上查到的不使用回调函数的select示例:
char **dbresult; int j,nrow,ncolumn,index;//select table ret = sqlite3_get_table(db,"select * from t",&dbresult,&nrow,&ncolumn,&errmsg); if(ret == SQLITE_OK){ printf("query %i records.\n",nrow); index=ncolumn; for(i=0;i<nrow;i++){ printf("[%2i]",i); for(j=0;j<ncolumn;j++){ printf(" %s",dbresult[index]); index++; } printf("\n"); } } sqlite3_free_table(dbresult);
示例三
/************************************************************************* > File Name: example3.c > Author: AnSwEr > Mail: 1045837697@qq.com > Created Time: 2015年08月29日 星期六 20时44分10秒 ************************************************************************//* * 表的创建与删除,数据的插入,更新与删除。 */#include<stdio.h>#include<stdlib.h>#include"sqlite3.h"static print_info(void *params,int column_size,char **column_value,char **column_name){ int i; for(i=0;i<column_size;i++) printf("\t%s",column_value[i]); printf("\n"); return 0;}int main(void){ char *filename = "./first.db"; sqlite3 *pDB = NULL; int ret = 0; /*open*/ ret = sqlite3_open(filename,&pDB); if(ret != SQLITE_OK) { fprintf(stderr,"%s\n",sqlite3_errmsg(pDB)); exit(EXIT_FAILURE); } /*创建表*/ const char *create_table = "create table t(id int primary key,name vachar(128))"; char *errmsg = 0; ret = sqlite3_exec(pDB,create_table,NULL,NULL,&errmsg); if(ret != SQLITE_OK) fprintf(stderr,"create table error:%s\n",errmsg); sqlite3_free(errmsg); /*插入数据*/ const char *insert_data = "insert into t(id,name) values(1,'answer')"; ret = sqlite3_exec(pDB,insert_data,NULL,NULL,&errmsg); if(ret != SQLITE_OK) fprintf(stderr,"insert data error:%s\n",errmsg); /*查询表中数据*/ ret = sqlite3_exec(pDB,"select * from t",print_info,NULL,&errmsg); if(ret != SQLITE_OK) fprintf(stderr,"select error:%s\n",errmsg); printf("\n"); /*更新表中数据*/ const char *update_data = "update t set name='jack' where id=1"; ret = sqlite3_exec(pDB,update_data,NULL,NULL,&errmsg); if(ret != SQLITE_OK) fprintf(stderr,"update_data error:%s\n",errmsg); /*查询表中数据*/ ret = sqlite3_exec(pDB,"select * from t",print_info,NULL,&errmsg); if(ret != SQLITE_OK) fprintf(stderr,"select error:%s\n",errmsg); printf("\n"); /*删除数据*/ const char *delete_data = "delete from t where id = 1"; ret = sqlite3_exec(pDB,delete_data,NULL,NULL,&errmsg); if(ret != SQLITE_OK) fprintf(stderr,"delete data error:%s\n",errmsg); /*查询受上次操作影响的记录数*/ printf("delete data records:%i\n",sqlite3_changes(pDB)); printf("\n"); /*删除表*/ const char *drop_table = "drop table if exists t"; ret = sqlite3_exec(pDB,drop_table,NULL,NULL,&errmsg); if(ret != SQLITE_OK) fprintf(stderr,"drop table error:%s\n",errmsg); /*close*/ if(pDB != NULL) { sqlite3_close(pDB); pDB = NULL; } return 0;}
示例三演示创建\删除表,数据的插入、更新与删除。
预编译操作
注意:sqlite3_exec中已经封装了预编译操作,直接使用即可,预编译操作只需稍作了解。
网上查了很多sqlite的预编译操作的例子,比较复杂,大致可以分为以下几个步骤:
1. 通过sqlite3_prepare创建一个sqlite3_stmt对象
2. 通过sqlite3_bind_*()绑定预编译字段的值
3. 通过sqlite3_step()执行SQL语句
4. 通过sqlite3_reset()重置预编译语句,重复操作2多次
5. 通过sqlite3_finalize()销毁资源
下面依次来看看这些函数。
sqlite3_prepare原型:
int sqlite3_prepare( sqlite3* pDB, /* 成功打开的数据库句柄 */ const char* sql, /* UTF8编码的 SQL 语句 */ int nbytes, /* 参数 sql 的字节数, 包含 '\0' */ sqlite3_stmt** ppStmt, /* 输出:预编译语句句柄 */ const char** pszTail /* 输出:指向 sql 语句中未使用的部分 */);
说明:
如果nbytes小于0, sql 语句则以第一个 ‘\0’终结。如果它非负,,则为读取的最大长度.。当nbytes 大于 0 时,则读取指定长度,如果’\0’先被读到,则以’\0’结束。如果用户知道被传入的 sql 语句是以 ‘\0’ 结尾的,那么有一个更好的做法是:把nbytes的值设为该字符串的长度(包含’\0’),这样可以避免 SQLite 复制该字符串的一份拷贝, 以提高程序的效率。
如果 pszTail 不为 NULL, 则 *pszTail 指向 sql 中第一个被传入的 SQL 语句的结尾。该函数只编译 sql 的第一个语句, 所以 *pszTail 指向的内容则是未被编译的。
*ppStmt 指向一条可以被 sqlie3_step() 函数使用的预编译语句.。如果有错误发生, pszStmt 的值为*NULL。
调用者应该使用 sqlite3_finalize() 删掉被预编译的语句。
如果函数成功, 返回 SQLITE_OK, 否则返回一个错误码。
sqlite3_bind_*有多种形式,分别对应不同的数据类型:
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, 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 n, void(*)(void*));int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
预编译SQL语句中可以包含如下几种形式:
??NNN:VVV@VVV$VVV
NNN代表数字,VVV代表字符串.
如果是?或者?NNN,那么可以直接sqlite3_bind_*()进行操作,如果是字符串,还需要通过sqlite3_bind_parameter_index()获取对应的index,然后再调用sqlite3_bind_*()操作。这通常用于构造不定条件的SQL语句(动态SQL语句)。
int sqlite3_step原型:
int sqlite3_step( sqlite3_stmt* ppStmt /* 一条被预编译的 sql 语句 */);
说明:
当一条语句被 sqlite3_prepare() 或其相关的函数预编译后, sqlite3_step() 必须被调用一次或多次来评估该预编译语句。
该函数的详细行为依赖于由 sqlite3_prepare()(或其相关的函数) 产生的是一条怎样的预编译语句。
返回值:
SQLITE_BUSY:忙碌. 数据库引擎无法锁定数据去完成其工作。但可以多次尝试。
SQLITE_DONE:完成. sql 语句已经被成功地执行。在调用 sqlite_reset() 之前, 当前预编译的语句不应该被 sqlite3_step() 再次调用。
SQLITE_ROW:查询时产生了结果。此时可以通过相关的”数据访问函数(column access functions)”来取得数据. sqlite3_step() 的再一次调用将取得下一条查询结果。
SQLITE_ERROR:发生了错误。 此时可以通过 sqlite3_errmmsg() 取得相关的错误信息. sqlite3_step() 不能被再次调用。
SQLITE_MISUSE:不正确的库的使用. 该函数使用不当。
sqlite3_finalize原型:
int sqlite3_finalize( sqlite3_stmt* pStmt /* 被预编译的语句 */);
说明:
该函数用来删除一条被预编译的 sql 语句。
预编译实现代码:
int i = 0; sqlite3_stmt *stmt; char ca[255]; //预编译操作 sqlite3_prepare_v2(db,"insert into t(id,msg) values(?,?)",-1,&stmt,0); for(i=10;i<20;i++){ sprintf(ca,"HELLO#%i",i); sqlite3_bind_int(stmt,1,i); sqlite3_bind_text(stmt,2,ca,strlen(ca),NULL); sqlite3_step(stmt); sqlite3_reset(stmt); } sqlite3_finalize(stmt); stmt = NULL;
总结
上文列出的是一些最基本精简的C语言API,sqlite为C语言一共提供了200多个API。不过,上述这些API对一般的开发者而言已经足够了,如果你还有更多的需求,那就请查阅前言中给出的源代码文件(sqlite3.c,sqlite3.h)。
反馈与建议
- 微博:@AnSwEr不是答案
- github:AnSwErYWJ
- 博客:AnSwEr不是答案的专栏
- Linux平台上SQLite数据库教程(二)——C语言API介绍
- Linux平台上SQLite数据库教程(二)——C语言API介绍
- Linux平台上SQLite数据库教程(二)——C语言API介绍
- Linux平台上SQLite数据库教程(一)——终端使用篇
- Linux平台上SQLite数据库教程(一)——终端使用篇
- Linux平台上SQLite数据库教程(一)——终端使用篇
- SQLite学习3_Linux平台上SQLite数据库教程(一)——终端使用篇
- sqlite-C语言API介绍
- Sqlite数据库在各种平台下的C语言应用程序开发(windows,linux,arm-linux)
- C API--linux上c语言读取数据库内容(mysql)
- Linux C语言操作SQLite数据库
- SQlite数据库的C编程接口(二) 数据库连接 ——《Using SQlite》读书笔记
- SQlite数据库的C编程接口(二) 数据库连接 ——《Using SQlite》读书笔记
- SQlite数据库的C编程接口(二) 数据库连接 ——《Using SQlite》读书笔记
- hjr教程-Android(二):Sqlite数据库
- hjr教程-Android(二):Sqlite数据库
- Android SQLite数据库—SQLiteOpenHelper(二)
- 在ARM-Linux平台上移植SQLite(上)
- Wpf ImageSource对象与Bitmap对象的互相转换
- 指针算术
- 迭代器Iterator
- Codeforces Round #251 (Div. 2) 439D Devu and his Brother(脑洞)
- HTML/CSS基础
- Linux平台上SQLite数据库教程(二)——C语言API介绍
- POJ 2184Cow Exhibition(01背包变形)
- linux学习笔记1-虚拟机安装 UBUNTU u盘无法识别
- 【more effective c++读书笔记】【第3章】异常(2)
- Android RecyclerView 使用完全解析 体验艺术般的控件
- ORA-00001: unique constraint (...) violated并不一定是数据冲突
- Linux下创建用户命令
- 异步I/O之asyncore
- sizeof(struct)说明