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
通常情况下callbackselect操作中会使用到,如果不需要回调函数。第三第四个参数设为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不是答案的专栏
0 0