sqlite之我见--CC++ API接口示例

sqlite之我见--CC++ API接口示例,第1张

概述转载自:http://www.voidcn.com/article/p-yqwmkucf-og.html 在之前的两篇博文中,分别介绍了SQLITE的基础知识和 *** 作,C/C++ 的一些常用API sqlite之我见--简单介绍与基本 *** 作 sqlite之我见--C/C++ API接口介绍  本文中,我会给大家用几个小程序示例SQLITE C/C++ API的使用。 1.我们看下最简单的sqlite程

转载自:http://www.jb51.cc/article/p-yqwmkucf-og.html

在之前的两篇博文中,分别介绍了sqlITE的基础知识和 *** 作,C/C++ 的一些常用API

sqlite之我见--简单介绍与基本 *** 作

sqlite之我见--C/C++ API接口介绍


本文中,我会给大家用几个小程序示例sqlITE C/C++ API的使用。

1.我们看下最简单的sqlite程序,通过sqlite3_open, sqlite3_exec, sqlite3_close来实现一个简单的数据库 *** 作。
/*  * file:   sqlite_test.cpp * Author: Carl * * Created on September 20,2012,3:28 PM */#include <cstdlib>#include <cstdio>#include <sqlite3.h>static int _sql_callback(voID *notused,int argc,char **argv,char **szColname){    int i = 0;        printf("notused:0x%x,argc:%d\n",notused,argc);    for (i = 0; i < argc; i++)    {        printf("%s = %s\n",szColname[i],argv[i] == 0 ? "NulL" : argv[i]);    }    printf("\n");        return 0;}/* *  */int main(int argc,char** argv){    const char *ssql1 = "create table users(userID varchar(20) PRIMARY KEY,age int,birthday datetime);";    const char *ssql2 = "insert into users values('wang',20,'1989-5-4');";    const char *ssql3 = "select * from users;";        sqlite3 *db = 0;    char *pErrMsg = 0;    int ret = 0;        //连接数据库    ret = sqlite3_open("./test.db",&db);    if (ret != sqlITE_OK)    {        fprintf(stderr,"无法打开数据库:%s\n",sqlite3_errmsg(db));        sqlite3_close(db);        return 1;    }    printf("数据库连接成功\n");        //执行建表sql    ret = sqlite3_exec(db,ssql1,_sql_callback,&pErrMsg);    if (ret != sqlITE_OK)    {        fprintf(stderr,"sql create error: %s\n",pErrMsg);        sqlite3_free(pErrMsg); //这个要的哦,要不然会内存泄露的哦!!!        sqlite3_close(db);        return 1;    }    printf("数据库建表成功!!\n");        //执行插入数据    ret = sqlite3_exec(db,ssql2,"sql insert error: %s\n",pErrMsg);        sqlite3_free(pErrMsg); //这个要的哦,要不然会内存泄露的哦!!!        sqlite3_close(db);        return 1;    }    printf("数据库插入数据成功!\n");        //执行查询 *** 作    ret = sqlite3_exec(db,ssql3,"sql error: %s\n",pErrMsg);        sqlite3_free(pErrMsg);        sqlite3_close(db);        return 1;    }    printf("数据库查询成功!!\n");        //关闭数据库    sqlite3_close(db);    db = 0;        return 0;}


运行结果如下结果:

[carl@Fedora sqlite]$ g++ sqlite_test.cpp -lsqlite3[carl@Fedora sqlite]$ ./a.out 数据库连接成功数据库建表成功!!数据库插入数据成功!notused:0x0,argc:3userID = wangage = 20birthday = 1989-5-4数据库查询成功!![carl@Fedora sqlite]$


2. 我们再看一个在sqlite上是有事务来实现原子 *** 作的的例子,

代码如下:

/*  * file:   sqlite_test.cpp * Author: Carl * * Created on 2012年9月22日,上午7:50 */#include <cstdlib>#include <cstdio>#include <sqlite3.h>static int _sql_callback(voID *notused,argv[i] == 0 ? "NulL" : argv[i]);    }    printf("\n");        return 0;}/* *  */int main(int argc,char** argv){    const char *ssql1 = "create table test_for_cpp (ID int,name varchar(10),age int);";    char sql[100] = {0};    sqlite3 *db = NulL;    char *pErrMsg = NulL;    int ret = 0;    bool is_success = true;    const char *ssql3 = "select * from test_for_cpp;";          ret = sqlite3_open("./test.db",&db);    if (sqlITE_OK != ret)    {        fprintf(stderr,"无法打开数据库: %s\n",sqlite3_errmsg(db));        sqlite3_close(db);        return 1;    }    printf("数据库连接成功\n");          ret = sqlite3_exec(db,NulL,&pErrMsg);    if (sqlITE_OK != ret)    {        fprintf(stderr,pErrMsg);        sqlite3_free(pErrMsg);        sqlite3_close(db);        return 1;    }    printf("数据库建表成功!!\n");          sqlite3_exec(db,"begin;",&pErrMsg); //开启事务    if (sqlITE_OK != ret)    {        fprintf(stderr,"sql begin error: %s\n",pErrMsg);        sqlite3_free(pErrMsg);        sqlite3_close(db);        return 1;    }    printf("数据库开启事务成功!!\n");          for (int i = 0; i < 10; i++)    {        sprintf(sql,"insert into test_for_cpp(ID,name,age) values(%d,\"%s\",%d);",i,"Carl",i);        ret = sqlite3_exec(db,sql,&pErrMsg);        if (sqlITE_OK != ret)        {            is_success = false;            fprintf(stderr,"for %d time error: %s\n",pErrMsg);            sqlite3_free(pErrMsg);            break;        }    }        if (is_success)    {        sqlite3_exec(db,"commit;",0);        printf("数据库插入数据成功!\n");      }    else    {        sqlite3_exec(db,"rollback;",0);        printf("数据库插入数据失败!\n");      }        ret = sqlite3_exec(db,"sql ERROR: %s\n",pErrMsg);        sqlite3_free(pErrMsg);        sqlite3_close(db);        return 1;    }    printf("数据库查询成功!!\n");          sqlite3_close(db);    db = 0;        return 0;}


运行结果:

[carl@Fedora sqlite]$ g++ sqlite_test.cpp -lsqlite3[carl@Fedora sqlite]$ ./a.out 数据库连接成功数据库建表成功!!数据库开启事务成功!!数据库插入数据成功!notused:0x0,argc:3ID = 0name = Carlage = 0notused:0x0,argc:3ID = 1name = Carlage = 1notused:0x0,argc:3ID = 2name = Carlage = 2notused:0x0,argc:3ID = 3name = Carlage = 3notused:0x0,argc:3ID = 4name = Carlage = 4notused:0x0,argc:3ID = 5name = Carlage = 5notused:0x0,argc:3ID = 6name = Carlage = 6notused:0x0,argc:3ID = 7name = Carlage = 7notused:0x0,argc:3ID = 8name = Carlage = 8notused:0x0,argc:3ID = 9name = Carlage = 9数据库查询成功!![carl@Fedora sqlite]$ 


3. 我们接着看一下如何能够更好的使用语句参数来 *** 作sqlite数据库,用sqlite3_prepare_v2,sqlite3_bind_*,sqlite3_step,sqlite3_column_*等接口来实现对数据库的 *** 作。

代码如下:里面的注释,有兴趣的可以试着打开试一下,但要记得注释掉相关的重复功能的语句哦。

/*  * file:   sqlite_test2.cpp * Author: Carl * * Created on September 21,3:12 PM */#include <cstdlib>#include <cstdio>#include <cstring>#include <sqlite3.h>static int _sql_callback(voID *notused,char** argv){    sqlite3 *conn = NulL;    sqlite3_stmt *stmt = NulL;    char *err_msg = NulL;    int ret = 0;        char col_types[][10] = {"","Interger","float","Text","Blob","NulL"};        ret = sqlite3_open("./test.db",&conn);    if (sqlITE_OK != ret)    {        fprintf(stderr,"sqlite open err,%d\n",ret);        return 1;    }    printf("打开数据库成功!!!\n");    //    ret = sqlite3_prepare_v2(conn,"SELECT * FROM [test_for_cpp] WHERE [name]==:name",-1,&stmt,(const char **)&err_msg);    ret = sqlite3_prepare_v2(conn,"SELECT * FROM [test_for_cpp] WHERE [name]==?2",(const char **)&err_msg);    if (sqlITE_OK != ret)    {        fprintf(stderr,"sqlite prepare error: %s\n",err_msg);        sqlite3_free(err_msg);        sqlite3_close(conn);        return 1;    }//    printf("数据库语句对象编译成功!!!%d\n",sqlite3_bind_parameter_index(stmt,":name"));    printf("数据库语句对象编译成功!!!\n");        ret = sqlite3_bind_text(stmt,2,4,sqlITE_STATIC);    if (sqlITE_OK != ret)    {        fprintf(stderr,"sqlite bind error: %d\n",ret);        sqlite3_close(conn);        return 1;    }    printf("数据库语句对象bind成功!!!\n");        while (ret = sqlite3_step(stmt),ret == sqlITE_ROW)    {        int col_count = sqlite3_column_count(stmt); //结果集中列的数量        printf("列数:%d\t",col_count);        const char *col_0_name = sqlite3_column_name(stmt,0); //获取列名        printf("列名:%s\t",col_0_name);        int ID = sqlite3_column_int(stmt,0);        printf("ID值:%d\t",ID);        int ID_type = sqlite3_column_type(stmt,0); //获取列数据类型        printf("ID类型:%d\t",ID_type);                const char *col_2_name = sqlite3_column_name(stmt,2);        int age = sqlite3_column_int(stmt,2);        int age_type = sqlite3_column_type(stmt,2);                const char *col_1_name = sqlite3_column_name(stmt,1);        char name[80];        strncpy(name,(const char *)sqlite3_column_text(stmt,1),80);        int name_type = sqlite3_column_type(stmt,1);                //打印结果        printf("col_count: %d,%s = %d(%s),%s = %s(%s),%s = %d(%s)\n",col_count,col_0_name,ID,col_types[ID_type],col_1_name,col_types[name_type],col_2_name,age,col_types[age_type]);    }        fprintf(stderr,"sqlite step exit with %d\n",ret);    sqlite3_finalize(stmt);    sqlite3_close(conn);        return 0;}


运行结果如下:

[carl@Fedora sqlite]$ g++ sqlite_test2.cpp -lsqlite3[carl@Fedora sqlite]$ ./a.out 打开数据库成功!!!数据库语句对象编译成功!!!数据库语句对象bind成功!!!列数:3	列名:ID	ID值:0	ID类型:1	col_count: 3,ID = 0(Interger),name = Carl(Text),age = 0(Interger)列数:3	列名:ID	ID值:1	ID类型:1	col_count: 3,ID = 1(Interger),age = 1(Interger)列数:3	列名:ID	ID值:2	ID类型:1	col_count: 3,ID = 2(Interger),age = 2(Interger)列数:3	列名:ID	ID值:3	ID类型:1	col_count: 3,ID = 3(Interger),age = 3(Interger)列数:3	列名:ID	ID值:4	ID类型:1	col_count: 3,ID = 4(Interger),age = 4(Interger)列数:3	列名:ID	ID值:5	ID类型:1	col_count: 3,ID = 5(Interger),age = 5(Interger)列数:3	列名:ID	ID值:6	ID类型:1	col_count: 3,ID = 6(Interger),age = 6(Interger)列数:3	列名:ID	ID值:7	ID类型:1	col_count: 3,ID = 7(Interger),age = 7(Interger)列数:3	列名:ID	ID值:8	ID类型:1	col_count: 3,ID = 8(Interger),age = 8(Interger)列数:3	列名:ID	ID值:9	ID类型:1	col_count: 3,ID = 9(Interger),age = 9(Interger)sqlite step exit with 101 //101意思为sqlITE_DONE[carl@Fedora sqlite]$ 


下面解释下为什么要学会这种能够细致控制sqlite的方法(即使用语句参数),主要有以下几个优点:

(1) 使用“语句参数”方式,具有更高的安全性,可以有效防止“sql注入攻击”。 “sql注入攻击”要想达到目的,就必须让attack value随着sql命令字符串一起传送进sql解析器。黑客如果在一条sql命令字符串被送入到sqlite3_prepare函数之前,利用c字符串处理函数等途径将attack value注入其中,而在sqlite3_prepare函数之中进行解析(parse),就可以达到攻击目的。而使用“语句参数”方式,被传送到sqlite3_prepare函数的只是sql命令字符串中的参数符号(如:“?”),而不是具体的值。在sqlite3_prepare函数执行之后,才会使用bind函数给参数符号绑定具体的值,这就可以避免attack value随着sql命令字符串一起在sqlite3_prepare函数中被解析,从而有效躲避“sql注入攻击”。
(2)使用“语句参数”方式,可以更快的完成值替换。

(3)使用“语句参数”方式,更节省内存。原因是使用如snprintf函数,需要一个sql命令模板,一块足够大的输出缓存,而且字符串处理函数需要工作内存(working memory),除此之外对于整形,浮点型,特别是BLOBs,经常会占用更多的空间。

总结

以上是内存溢出为你收集整理的sqlite之我见--C/C++ API接口示例全部内容,希望文章能够帮你解决sqlite之我见--C/C++ API接口示例所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/sjk/1163481.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-01
下一篇 2022-06-01

发表评论

登录后才能评论

评论列表(0条)

保存