sqlite之我见--C/C++ API接口示例 .

前端之家收集整理的这篇文章主要介绍了sqlite之我见--C/C++ API接口示例 .前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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

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

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


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

1.我们看下最简单的sqlite程序,通过sqlite3_open, sqlite3_exec, sqlite3_close来实现一个简单的数据库操作。

  1. /*
  2. *File:sqlite_test.cpp
  3. *Author:Carl
  4. *
  5. *CreatedonSeptember20,2012,3:28PM
  6. */
  7. #include<cstdlib>
  8. #include<cstdio>
  9. #include<sqlite3.h>
  10. staticint_sql_callback(void*notused,intargc,char**argv,char**szColName)
  11. {
  12. inti=0;
  13. printf("notused:0x%x,argc:%d\n",notused,argc);
  14. for(i=0;i<argc;i++)
  15. {
  16. printf("%s=%s\n",szColName[i],argv[i]==0?"NULL":argv[i]);
  17. }
  18. printf("\n");
  19. return0;
  20. }
  21. /*
  22. *
  23. */
  24. intmain(intargc,char**argv)
  25. {
  26. constchar*ssql1="createtableusers(useridvarchar(20)PRIMARYKEY,ageint,birthdaydatetime);";
  27. constchar*ssql2="insertintousersvalues('wang',20,'1989-5-4');";
  28. constchar*ssql3="select*fromusers;";
  29. sqlite3*db=0;
  30. char*pErrMsg=0;
  31. intret=0;
  32. //连接数据库
  33. ret=sqlite3_open("./test.db",&db);
  34. if(ret!=sqlITE_OK)
  35. {
  36. fprintf(stderr,"无法打开数据库:%s\n",sqlite3_errmsg(db));
  37. sqlite3_close(db);
  38. return1;
  39. }
  40. printf("数据库连接成功\n");
  41. //执行建表sql
  42. ret=sqlite3_exec(db,ssql1,_sql_callback,&pErrMsg);
  43. if(ret!=sqlITE_OK)
  44. {
  45. fprintf(stderr,"sqlcreateerror:%s\n",pErrMsg);
  46. sqlite3_free(pErrMsg);//这个要的哦,要不然会内存泄露的哦!!!
  47. sqlite3_close(db);
  48. return1;
  49. }
  50. printf("数据库建表成功!!\n");
  51. //执行插入数据
  52. ret=sqlite3_exec(db,ssql2,&pErrMsg);
  53. if(ret!=sqlITE_OK)
  54. {
  55. fprintf(stderr,"sqlinserterror:%s\n",pErrMsg);
  56. sqlite3_free(pErrMsg);//这个要的哦,要不然会内存泄露的哦!!!
  57. sqlite3_close(db);
  58. return1;
  59. }
  60. printf("数据库插入数据成功!\n");
  61. //执行查询操作
  62. ret=sqlite3_exec(db,ssql3,"sqlerror:%s\n",pErrMsg);
  63. sqlite3_free(pErrMsg);
  64. sqlite3_close(db);
  65. return1;
  66. }
  67. printf("数据库查询成功!!\n");
  68. //关闭数据库
  69. sqlite3_close(db);
  70. db=0;
  71. return0;
  72. }

运行结果如下结果:

  1. [carl@Fedorasqlite]$g++sqlite_test.cpp-lsqlite3
  2. [carl@Fedorasqlite]$./a.out
  3. 数据库连接成功
  4. 数据库建表成功!!
  5. 数据库插入数据成功!
  6. notused:0x0,argc:3
  7. userid=wang
  8. age=20
  9. birthday=1989-5-4
  10. 数据库查询成功!!
  11. [carl@Fedorasqlite]$

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

代码如下:

  1. /*
  2. *File:sqlite_test.cpp
  3. *Author:Carl
  4. *
  5. *Createdon2012年9月22日,上午7:50
  6. */
  7. #include<cstdlib>
  8. #include<cstdio>
  9. #include<sqlite3.h>
  10. staticint_sql_callback(void*notused,argv[i]==0?"NULL":argv[i]);
  11. }
  12. printf("\n");
  13. return0;
  14. }
  15. /*
  16. *
  17. */
  18. intmain(intargc,char**argv)
  19. {
  20. constchar*ssql1="createtabletest_for_cpp(idint,namevarchar(10),ageint);";
  21. charsql[100]={0};
  22. sqlite3*db=NULL;
  23. char*pErrMsg=NULL;
  24. intret=0;
  25. boolis_success=true;
  26. constchar*ssql3="select*fromtest_for_cpp;";
  27. ret=sqlite3_open("./test.db",&db);
  28. if(sqlITE_OK!=ret)
  29. {
  30. fprintf(stderr,sqlite3_errmsg(db));
  31. sqlite3_close(db);
  32. return1;
  33. }
  34. printf("数据库连接成功\n");
  35. ret=sqlite3_exec(db,NULL,&pErrMsg);
  36. if(sqlITE_OK!=ret)
  37. {
  38. fprintf(stderr,pErrMsg);
  39. sqlite3_free(pErrMsg);
  40. sqlite3_close(db);
  41. return1;
  42. }
  43. printf("数据库建表成功!!\n");
  44. sqlite3_exec(db,"begin;",&pErrMsg);//开启事务
  45. if(sqlITE_OK!=ret)
  46. {
  47. fprintf(stderr,"sqlbeginerror:%s\n",pErrMsg);
  48. sqlite3_free(pErrMsg);
  49. sqlite3_close(db);
  50. return1;
  51. }
  52. printf("数据库开启事务成功!!\n");
  53. for(inti=0;i<10;i++)
  54. {
  55. sprintf(sql,"insertintotest_for_cpp(id,name,age)values(%d,\"%s\",%d);",i,"Carl",i);
  56. ret=sqlite3_exec(db,sql,&pErrMsg);
  57. if(sqlITE_OK!=ret)
  58. {
  59. is_success=false;
  60. fprintf(stderr,"for%dtimeerror:%s\n",pErrMsg);
  61. sqlite3_free(pErrMsg);
  62. break;
  63. }
  64. }
  65. if(is_success)
  66. {
  67. sqlite3_exec(db,"commit;",0);
  68. printf("数据库插入数据成功!\n");
  69. }
  70. else
  71. {
  72. sqlite3_exec(db,"rollback;",0);
  73. printf("数据库插入数据失败!\n");
  74. }
  75. ret=sqlite3_exec(db,"sqlERROR:%s\n",pErrMsg);
  76. sqlite3_free(pErrMsg);
  77. sqlite3_close(db);
  78. return1;
  79. }
  80. printf("数据库查询成功!!\n");
  81. sqlite3_close(db);
  82. db=0;
  83. return0;
  84. }

运行结果:
  1. [carl@Fedorasqlite]$g++sqlite_test.cpp-lsqlite3
  2. [carl@Fedorasqlite]$./a.out
  3. 数据库连接成功
  4. 数据库建表成功!!
  5. 数据库开启事务成功!!
  6. 数据库插入数据成功!
  7. notused:0x0,argc:3
  8. id=0
  9. name=Carl
  10. age=0
  11. notused:0x0,argc:3
  12. id=1
  13. name=Carl
  14. age=1
  15. notused:0x0,argc:3
  16. id=2
  17. name=Carl
  18. age=2
  19. notused:0x0,argc:3
  20. id=3
  21. name=Carl
  22. age=3
  23. notused:0x0,argc:3
  24. id=4
  25. name=Carl
  26. age=4
  27. notused:0x0,argc:3
  28. id=5
  29. name=Carl
  30. age=5
  31. notused:0x0,argc:3
  32. id=6
  33. name=Carl
  34. age=6
  35. notused:0x0,argc:3
  36. id=7
  37. name=Carl
  38. age=7
  39. notused:0x0,argc:3
  40. id=8
  41. name=Carl
  42. age=8
  43. notused:0x0,argc:3
  44. id=9
  45. name=Carl
  46. age=9
  47. 数据库查询成功!!
  48. [carl@Fedorasqlite]$

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

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

  1. /*
  2. *File:sqlite_test2.cpp
  3. *Author:Carl
  4. *
  5. *CreatedonSeptember21,3:12PM
  6. */
  7. #include<cstdlib>
  8. #include<cstdio>
  9. #include<cstring>
  10. #include<sqlite3.h>
  11. staticint_sql_callback(void*notused,char**szColName)
  12. {
  13. inti=0;
  14. printf("notused:0x%x,argc);
  15. for(i=0;i<argc;i++)
  16. {
  17. printf("%s=%s\n",argv[i]==0?"NULL":argv[i]);
  18. }
  19. printf("\n");
  20. return0;
  21. }
  22. /*
  23. *
  24. */
  25. intmain(intargc,char**argv)
  26. {
  27. sqlite3*conn=NULL;
  28. sqlite3_stmt*stmt=NULL;
  29. char*err_msg=NULL;
  30. intret=0;
  31. charcol_types[][10]={"","Interger","Float","Text","Blob","NULL"};
  32. ret=sqlite3_open("./test.db",&conn);
  33. if(sqlITE_OK!=ret)
  34. {
  35. fprintf(stderr,"sqliteopenerr,%d\n",ret);
  36. return1;
  37. }
  38. printf("打开数据库成功!!!\n");
  39. //ret=sqlite3_prepare_v2(conn,"SELECT*FROM[test_for_cpp]WHERE[name]==:name",-1,&stmt,(constchar**)&err_msg);
  40. ret=sqlite3_prepare_v2(conn,"SELECT*FROM[test_for_cpp]WHERE[name]==?2",(constchar**)&err_msg);
  41. if(sqlITE_OK!=ret)
  42. {
  43. fprintf(stderr,"sqliteprepareerror:%s\n",err_msg);
  44. sqlite3_free(err_msg);
  45. sqlite3_close(conn);
  46. return1;
  47. }
  48. //printf("数据库语句对象编译成功!!!%d\n",sqlite3_bind_parameter_index(stmt,":name"));
  49. printf("数据库语句对象编译成功!!!\n");
  50. ret=sqlite3_bind_text(stmt,2,4,sqlITE_STATIC);
  51. if(sqlITE_OK!=ret)
  52. {
  53. fprintf(stderr,"sqlitebinderror:%d\n",ret);
  54. sqlite3_close(conn);
  55. return1;
  56. }
  57. printf("数据库语句对象bind成功!!!\n");
  58. while(ret=sqlite3_step(stmt),ret==sqlITE_ROW)
  59. {
  60. intcol_count=sqlite3_column_count(stmt);//结果集中列的数量
  61. printf("列数:%d\t",col_count);
  62. constchar*col_0_name=sqlite3_column_name(stmt,0);//获取列名
  63. printf("列名:%s\t",col_0_name);
  64. intid=sqlite3_column_int(stmt,0);
  65. printf("id值:%d\t",id);
  66. intid_type=sqlite3_column_type(stmt,0);//获取列数据类型
  67. printf("id类型:%d\t",id_type);
  68. constchar*col_2_name=sqlite3_column_name(stmt,2);
  69. intage=sqlite3_column_int(stmt,2);
  70. intage_type=sqlite3_column_type(stmt,2);
  71. constchar*col_1_name=sqlite3_column_name(stmt,1);
  72. charname[80];
  73. strncpy(name,(constchar*)sqlite3_column_text(stmt,1),80);
  74. intname_type=sqlite3_column_type(stmt,1);
  75. //打印结果
  76. printf("col_count:%d,%s=%d(%s),%s=%s(%s),%s=%d(%s)\n",
  77. col_count,col_0_name,id,col_types[id_type],col_1_name,
  78. col_types[name_type],col_2_name,age,col_types[age_type]);
  79. }
  80. fprintf(stderr,"sqlitestepexitwith%d\n",ret);
  81. sqlite3_finalize(stmt);
  82. sqlite3_close(conn);
  83. return0;
  84. }
@H_270_2301@/* * 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",(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",":name")); printf("数据库语句对象编译成功!!!\n"); ret = sqlite3_bind_text(stmt,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,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_types[name_type],col_types[age_type]); } fprintf(stderr,"sqlite step exit with %d\n",ret); sqlite3_finalize(stmt); sqlite3_close(conn); return 0; }
运行结果如下:
  1. [carl@Fedorasqlite]$g++sqlite_test2.cpp-lsqlite3
  2. [carl@Fedorasqlite]$./a.out
  3. 打开数据库成功!!!
  4. 数据库语句对象编译成功!!!
  5. 数据库语句对象bind成功!!!
  6. 列数:3列名:idid值:0id类型:1col_count:3,id=0(Interger),name=Carl(Text),age=0(Interger)
  7. 列数:3列名:idid值:1id类型:1col_count:3,id=1(Interger),age=1(Interger)
  8. 列数:3列名:idid值:2id类型:1col_count:3,id=2(Interger),age=2(Interger)
  9. 列数:3列名:idid值:3id类型:1col_count:3,id=3(Interger),age=3(Interger)
  10. 列数:3列名:idid值:4id类型:1col_count:3,id=4(Interger),age=4(Interger)
  11. 列数:3列名:idid值:5id类型:1col_count:3,id=5(Interger),age=5(Interger)
  12. 列数:3列名:idid值:6id类型:1col_count:3,id=6(Interger),age=6(Interger)
  13. 列数:3列名:idid值:7id类型:1col_count:3,id=7(Interger),age=7(Interger)
  14. 列数:3列名:idid值:8id类型:1col_count:3,id=8(Interger),age=8(Interger)
  15. 列数:3列名:idid值:9id类型:1col_count:3,id=9(Interger),age=9(Interger)
  16. sqlitestepexitwith101//101意思为sqlITE_DONE
  17. [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,经常会占用更多的空间。


水平有限,如果有朋友发现错误,欢迎留言交流。
转载请保留本文链接,如果觉得我的文章能帮到您,请顶一下。,谢谢。

猜你在找的Sqlite相关文章