本文中,我会给大家用几个小程序示例SQLITE C/C++ API的使用。
1.我们看下最简单的sqlite程序,通过sqlite3_open, sqlite3_exec, sqlite3_close来实现一个简单的数据库操作。
[cpp]view plaincopy
-
-
-
-
-
-
-
- #include<cstdlib>
- #include<cstdio>
- #include<sqlite3.h>
- staticint_sql_callback(void*notused,intargc,char**argv,char**szColName)
- {
- inti=0;
- printf("notused:0x%x,argc:%dn",notused,argc);
- for(i=0;i<argc;i++)
- {
- printf("%s=%sn",szColName[i],argv[i]==0?"NULL":argv[i]);
- }
- printf("n");
-
- return0;
-
-
- intmain(intargc,char**argv)
- constchar*sSQL1="createtableusers(useridvarchar(20)PRIMARYKEY,ageint,birthdaydatetime);";
- constchar*sSQL2="insertintousersvalues('wang',20,'1989-5-4');";
- constchar*sSQL3="select*fromusers;";
- sqlite3*db=0;
- char*pErrMsg=0;
- intret=0;
-
- ret=sqlite3_open("./test.db",&db);
- if(ret!=SQLITE_OK)
- fprintf(stderr,"无法打开数据库:%sn",sqlite3_errmsg(db));
- sqlite3_close(db);
- return1;
- printf("数据库连接成功n");
-
- ret=sqlite3_exec(db,sSQL1,_sql_callback,&pErrMsg);
- "SQLcreateerror:%sn",pErrMsg);
- sqlite3_free(pErrMsg);
- sqlite3_close(db);
- return1;
- }
- printf("数据库建表成功!!n");
-
- if(ret!=SQLITE_OK)
- "SQLinserterror:%sn",pErrMsg);
- sqlite3_free(pErrMsg);
- printf("数据库插入数据成功!n");
-
- "SQLerror:%sn",108); list-style:decimal-leading-zero outside; margin:0px!important; padding:0px 3px 0px 10px!important"> sqlite3_free(pErrMsg);
- printf("数据库查询成功!!n");
-
- db=0;
- return0;
- }
运行结果如下结果:
[plain]view plaincopy
- [carl@Fedorasqlite]$g++sqlite_test.cpp-lsqlite3
- [carl@Fedorasqlite]$./a.out
- 数据库连接成功
- 数据库建表成功!!
- 数据库插入数据成功!
- notused:0x0,argc:3
- userid=wang
- age=20
- birthday=1989-5-4
- 数据库查询成功!!
- [carl@Fedorasqlite]$
2. 我们再看一个在sqlite上是有事务来实现原子操作的的例子,
代码如下:
[cpp]view plaincopy
-
-
- char**argv)
- constchar*sSQL1="createtabletest_for_cpp(idint,namevarchar(10),ageint);";
- charsql[100]={0};
- sqlite3*db=NULL;
- char*pErrMsg=NULL;
- intret=0;
- boolis_success=true;
- constchar*sSQL3="select*fromtest_for_cpp;";
- if(SQLITE_OK!=ret)
- if(SQLITE_OK!=ret)
- sqlite3_free(pErrMsg);
- printf("数据库建表成功!!n");
- sqlite3_exec(db,"begin;",&pErrMsg);
- "SQLbeginerror:%sn",108); list-style:decimal-leading-zero outside; margin:0px!important; padding:0px 3px 0px 10px!important"> printf("数据库开启事务成功!!n");
- for(inti=0;i<10;i++)
- sprintf(sql,"insertintotest_for_cpp(id,name,age)values(%d,"%s",%d);",i,"Carl",i);
- is_success=false;
- "for%dtimeerror:%sn",108); list-style:decimal-leading-zero outside; margin:0px!important; padding:0px 3px 0px 10px!important"> break;
- if(is_success)
- "commit;",0);
- else
- "rollback;",0);
- printf("数据库插入数据失败!n");
- "SQLERROR:%sn",108); list-style:decimal-leading-zero outside; margin:0px!important; padding:0px 3px 0px 10px!important"> printf("数据库查询成功!!n");
- }
运行结果:
[plain]view plaincopy
- 数据库开启事务成功!!
- 数据库插入数据成功!
- id=0
- name=Carl
- age=0
- id=1
- name=Carl
- age=1
- id=2
- age=2
- id=3
- age=3
- id=4
- age=4
- id=5
- age=5
- id=6
- age=6
- id=7
- age=7
- id=8
- age=8
- id=9
- age=9
- [carl@Fedorasqlite]$
3. 我们接着看一下如何能够更好的使用语句参数来操作sqlite数据库,用sqlite3_prepare_v2,sqlite3_bind_*,sqlite3_step,sqlite3_column_*等接口来实现对数据库的操作。
代码如下:里面的注释,有兴趣的可以试着打开试一下,但要记得注释掉相关的重复功能的语句哦。
[cpp]view plaincopy
-
-
- #include<cstring>
- #include<sqlite3.h>
- char**szColName)
- inti=0;
- for(i=0;i<argc;i++)
- "NULL":argv[i]);
- printf("n");
- sqlite3*conn=NULL;
- sqlite3_stmt*stmt=NULL;
- char*err_msg=NULL;
- charcol_types[][10]={"","Interger","Float","Text","Blob","NULL"};
- "sqliteopenerr,%dn",ret);
- printf("打开数据库成功!!!n");
-
- ret=sqlite3_prepare_v2(conn,"SELECT*FROM[test_for_cpp]WHERE[name]==?2",(constchar**)&err_msg);
- "sqliteprepareerror:%sn",err_msg);
- sqlite3_free(err_msg);
- sqlite3_close(conn);
-
- printf("数据库语句对象编译成功!!!n");
- ret=sqlite3_bind_text(stmt,2,"Carl",4,SQLITE_STATIC);
- "sqlitebinderror:%dn",108); list-style:decimal-leading-zero outside; margin:0px!important; padding:0px 3px 0px 10px!important"> printf("数据库语句对象bind成功!!!n");
- while(ret=sqlite3_step(stmt),ret==SQLITE_ROW)
- intcol_count=sqlite3_column_count(stmt);
- printf("列数:%dt",col_count);
- constchar*col_0_name=sqlite3_column_name(stmt,0);
- printf("列名:%st",col_0_name);
- intid=sqlite3_column_int(stmt,108); list-style:decimal-leading-zero outside; margin:0px!important; padding:0px 3px 0px 10px!important"> printf("id值:%dt",id);
- intid_type=sqlite3_column_type(stmt,0);
- printf("id类型:%dt",id_type);
- constchar*col_2_name=sqlite3_column_name(stmt,2);
- intage=sqlite3_column_int(stmt,2);
- intage_type=sqlite3_column_type(stmt,108); list-style:decimal-leading-zero outside; margin:0px!important; padding:0px 3px 0px 10px!important"> constchar*col_1_name=sqlite3_column_name(stmt,1);
- charname[80];
- strncpy(name,(constchar*)sqlite3_column_text(stmt,1),80);
- intname_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]);
- "sqlitestepexitwith%dn",108); list-style:decimal-leading-zero outside; margin:0px!important; padding:0px 3px 0px 10px!important"> sqlite3_finalize(stmt);
- sqlite3_close(conn);
- }
运行结果如下:
[plain]view plaincopy
- [carl@Fedorasqlite]$g++sqlite_test2.cpp-lsqlite3
- 打开数据库成功!!!
- 数据库语句对象编译成功!!!
- 数据库语句对象bind成功!!!
- 列数:3列名:idid值:0id类型:1col_count:3,id=0(Interger),name=Carl(Text),age=0(Interger)
- 列数:3列名:idid值:1id类型:1col_count:3,id=1(Interger),age=1(Interger)
- 列数:3列名:idid值:2id类型:1col_count:3,id=2(Interger),age=2(Interger)
- 列数:3列名:idid值:3id类型:1col_count:3,id=3(Interger),age=3(Interger)
- 列数:3列名:idid值:4id类型:1col_count:3,id=4(Interger),age=4(Interger)
- 列数:3列名:idid值:5id类型:1col_count:3,id=5(Interger),age=5(Interger)
- 列数:3列名:idid值:6id类型:1col_count:3,id=6(Interger),age=6(Interger)
- 列数:3列名:idid值:7id类型:1col_count:3,id=7(Interger),age=7(Interger)
- 列数:3列名:idid值:8id类型:1col_count:3,id=8(Interger),age=8(Interger)
- 列数:3列名:idid值:9id类型:1col_count:3,id=9(Interger),age=9(Interger)
- sqlitestepexitwith101//101意思为SQLITE_DONE
- [carl@Fedorasqlite]$
下面解释下为什么要学会这种能够细致控制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,经常会占用更多的空间。
水平有限,如果有朋友发现错误,欢迎留言交流。
转载请保留本文链接,如果觉得我的文章能帮到您,请顶一下。,谢谢。
摘自 :http://blog.csdn.net/wzzfeitian/article/details/7993686 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|