sqlite函数接口


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

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

  1. /*  
  2.  * File:   sqlite_test.cpp 
  3.  * Author: Carl 
  4.  * 
  5.  * Created on September 20, 2012, 3:28 PM 
  6.  */  
  7.   
  8. #include <cstdlib>  
  9. #include <cstdio>  
  10. #include <sqlite3.h>  
  11.   
  12. static int _sql_callback(void *notused, int argc, char **argv, char **szColName)  
  13. {  
  14.     int i = 0;  
  15.       
  16.     printf("notused:0x%x, argc:%d\n", notused, argc);  
  17.     for (i = 0; i < argc; i++)  
  18.     {  
  19.         printf("%s = %s\n", szColName[i], argv[i] == 0 ? "NULL" : argv[i]);  
  20.     }  
  21.     printf("\n");  
  22.       
  23.     return 0;  
  24. }  
  25.   
  26. /* 
  27.  *  
  28.  */  
  29. int main(int argc, char** argv)  
  30. {  
  31.     const char *sSQL1 = "create table users(userid varchar(20) PRIMARY KEY, age int, birthday datetime);";  
  32.     const char *sSQL2 = "insert into users values('wang', 20, '1989-5-4');";  
  33.     const char *sSQL3 = "select * from users;";  
  34.       
  35.     sqlite3 *db = 0;  
  36.     char *pErrMsg = 0;  
  37.     int ret = 0;  
  38.       
  39.     //连接数据库  
  40.     ret = sqlite3_open("./test.db", &db);  
  41.     if (ret != SQLITE_OK)  
  42.     {  
  43.         fprintf(stderr, "无法打开数据库:%s\n", sqlite3_errmsg(db));  
  44.         sqlite3_close(db);  
  45.         return 1;  
  46.     }  
  47.     printf("数据库连接成功\n");  
  48.       
  49.     //执行建表SQL  
  50.     ret = sqlite3_exec(db, sSQL1, _sql_callback, 0, &pErrMsg);  
  51.     if (ret != SQLITE_OK)  
  52.     {  
  53.         fprintf(stderr, "SQL create error: %s\n", pErrMsg);  
  54.         sqlite3_free(pErrMsg); //这个要的哦,要不然会内存泄露的哦!!!  
  55.         sqlite3_close(db);  
  56.         return 1;  
  57.     }  
  58.     printf("数据库建表成功!!\n");  
  59.       
  60.     //执行插入数据  
  61.     ret = sqlite3_exec(db, sSQL2, _sql_callback, 0, &pErrMsg);  
  62.     if (ret != SQLITE_OK)  
  63.     {  
  64.         fprintf(stderr, "SQL insert error: %s\n", pErrMsg);  
  65.         sqlite3_free(pErrMsg); //这个要的哦,要不然会内存泄露的哦!!!  
  66.         sqlite3_close(db);  
  67.         return 1;  
  68.     }  
  69.     printf("数据库插入数据成功!\n");  
  70.       
  71.     //执行查询操作  
  72.     ret = sqlite3_exec(db, sSQL3, _sql_callback, 0, &pErrMsg);  
  73.     if (ret != SQLITE_OK)  
  74.     {  
  75.         fprintf(stderr, "SQL error: %s\n", pErrMsg);  
  76.         sqlite3_free(pErrMsg);  
  77.         sqlite3_close(db);  
  78.         return 1;  
  79.     }  
  80.     printf("数据库查询成功!!\n");  
  81.       
  82.     //关闭数据库  
  83.     sqlite3_close(db);  
  84.     db = 0;  
  85.       
  86.     return 0;  
  87. }  


运行结果如下结果:

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

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

代码如下:

  1. /*  
  2.  * File:   sqlite_test.cpp 
  3.  * Author: Carl 
  4.  * 
  5.  * Created on 2012年9月22日, 上午7:50 
  6.  */  
  7.   
  8. #include <cstdlib>  
  9. #include <cstdio>  
  10. #include <sqlite3.h>  
  11.   
  12. static int _sql_callback(void *notused, int argc, char **argv, char **szColName)  
  13. {  
  14.     int i = 0;  
  15.       
  16.     printf("notused:0x%x, argc:%d\n", notused, argc);  
  17.     for (i = 0; i < argc; i++)  
  18.     {  
  19.         printf("%s = %s\n", szColName[i], argv[i] == 0 ? "NULL" : argv[i]);  
  20.     }  
  21.     printf("\n");  
  22.       
  23.     return 0;  
  24. }  
  25.   
  26.   
  27. /* 
  28.  *  
  29.  */  
  30. int main(int argc, char** argv)  
  31. {  
  32.     const char *sSQL1 = "create table test_for_cpp (id int, name varchar(10), age int);";  
  33.     char sql[100] = {0};  
  34.     sqlite3 *db = NULL;  
  35.     char *pErrMsg = NULL;  
  36.     int ret = 0;  
  37.     bool is_success = true;  
  38.     const char *sSQL3 = "select * from test_for_cpp;";    
  39.       
  40.     ret = sqlite3_open("./test.db", &db);  
  41.     if (SQLITE_OK != ret)  
  42.     {  
  43.         fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));  
  44.         sqlite3_close(db);  
  45.         return 1;  
  46.     }  
  47.     printf("数据库连接成功\n");    
  48.       
  49.     ret = sqlite3_exec(db, sSQL1, NULL, 0, &pErrMsg);  
  50.     if (SQLITE_OK != ret)  
  51.     {  
  52.         fprintf(stderr, "SQL create error: %s\n", pErrMsg);  
  53.         sqlite3_free(pErrMsg);  
  54.         sqlite3_close(db);  
  55.         return 1;  
  56.     }  
  57.     printf("数据库建表成功!!\n");    
  58.       
  59.     sqlite3_exec(db, "begin;", _sql_callback, 0, &pErrMsg); //开启事务  
  60.     if (SQLITE_OK != ret)  
  61.     {  
  62.         fprintf(stderr, "SQL begin error: %s\n", pErrMsg);  
  63.         sqlite3_free(pErrMsg);  
  64.         sqlite3_close(db);  
  65.         return 1;  
  66.     }  
  67.     printf("数据库开启事务成功!!\n");    
  68.       
  69.     for (int i = 0; i < 10; i++)  
  70.     {  
  71.         sprintf(sql, "insert into test_for_cpp(id, name, age) values(%d, \"%s\", %d);", i, "Carl", i);  
  72.         ret = sqlite3_exec(db, sql, _sql_callback, 0, &pErrMsg);  
  73.         if (SQLITE_OK != ret)  
  74.         {  
  75.             is_success = false;  
  76.             fprintf(stderr, "for %d time error: %s\n", i, pErrMsg);  
  77.             sqlite3_free(pErrMsg);  
  78.             break;  
  79.         }  
  80.     }  
  81.       
  82.     if (is_success)  
  83.     {  
  84.         sqlite3_exec(db, "commit;", 0, 0, 0);  
  85.         printf("数据库插入数据成功!\n");    
  86.     }  
  87.     else  
  88.     {  
  89.         sqlite3_exec(db, "rollback;", 0, 0, 0);  
  90.         printf("数据库插入数据失败!\n");    
  91.     }  
  92.       
  93.     ret = sqlite3_exec(db, sSQL3, _sql_callback, 0, &pErrMsg);  
  94.     if (SQLITE_OK != ret)  
  95.     {  
  96.         fprintf(stderr, "SQL ERROR: %s\n", pErrMsg);  
  97.         sqlite3_free(pErrMsg);  
  98.         sqlite3_close(db);  
  99.         return 1;  
  100.     }  
  101.     printf("数据库查询成功!!\n");    
  102.       
  103.     sqlite3_close(db);  
  104.     db = 0;  
  105.       
  106.     return 0;  
  107. }  

运行结果:

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


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

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

  1. /*  
  2.  * File:   sqlite_test2.cpp 
  3.  * Author: Carl 
  4.  * 
  5.  * Created on September 21, 2012, 3:12 PM 
  6.  */  
  7.   
  8. #include <cstdlib>  
  9. #include <cstdio>  
  10. #include <cstring>  
  11. #include <sqlite3.h>  
  12.   
  13. static int _sql_callback(void *notused, int argc, char **argv, char **szColName)  
  14. {  
  15.     int i = 0;  
  16.       
  17.     printf("notused:0x%x, argc:%d\n", notused, argc);  
  18.     for (i = 0; i < argc; i++)  
  19.     {  
  20.         printf("%s = %s\n", szColName[i], argv[i] == 0 ? "NULL" : argv[i]);  
  21.     }  
  22.     printf("\n");  
  23.       
  24.     return 0;  
  25. }  
  26.   
  27. /* 
  28.  *  
  29.  */  
  30. int main(int argc, char** argv)  
  31. {  
  32.     sqlite3 *conn = NULL;  
  33.     sqlite3_stmt *stmt = NULL;  
  34.     char *err_msg = NULL;  
  35.     int ret = 0;  
  36.       
  37.     char col_types[][10] = {"""Interger""Float""Text""Blob""NULL"};  
  38.       
  39.     ret = sqlite3_open("./test.db", &conn);  
  40.     if (SQLITE_OK != ret)  
  41.     {  
  42.         fprintf(stderr, "sqlite open err, %d\n", ret);  
  43.         return 1;  
  44.     }  
  45.     printf("打开数据库成功!!!\n");  
  46.       
  47. //    ret = sqlite3_prepare_v2(conn, "SELECT * FROM [test_for_cpp] WHERE [name]==:name", -1, &stmt, (const char **)&err_msg);  
  48.     ret = sqlite3_prepare_v2(conn, "SELECT * FROM [test_for_cpp] WHERE [name]==?2", -1, &stmt, (const char **)&err_msg);  
  49.     if (SQLITE_OK != ret)  
  50.     {  
  51.         fprintf(stderr, "sqlite prepare error: %s\n", err_msg);  
  52.         sqlite3_free(err_msg);  
  53.         sqlite3_close(conn);  
  54.         return 1;  
  55.     }  
  56. //    printf("数据库语句对象编译成功!!!%d\n", sqlite3_bind_parameter_index(stmt, ":name"));  
  57.     printf("数据库语句对象编译成功!!!\n");  
  58.       
  59.     ret = sqlite3_bind_text(stmt, 2, "Carl", 4, SQLITE_STATIC);  
  60.     if (SQLITE_OK != ret)  
  61.     {  
  62.         fprintf(stderr, "sqlite bind error: %d\n", ret);  
  63.         sqlite3_close(conn);  
  64.         return 1;  
  65.     }  
  66.     printf("数据库语句对象bind成功!!!\n");  
  67.       
  68.     while (ret = sqlite3_step(stmt), ret == SQLITE_ROW)  
  69.     {  
  70.         int col_count = sqlite3_column_count(stmt); //结果集中列的数量  
  71.         printf("列数:%d\t", col_count);  
  72.         const char *col_0_name = sqlite3_column_name(stmt, 0); //获取列名  
  73.         printf("列名:%s\t", col_0_name);  
  74.         int id = sqlite3_column_int(stmt, 0);  
  75.         printf("id值:%d\t", id);  
  76.         int id_type = sqlite3_column_type(stmt, 0); //获取列数据类型  
  77.         printf("id类型:%d\t", id_type);  
  78.           
  79.         const char *col_2_name = sqlite3_column_name(stmt, 2);  
  80.         int age = sqlite3_column_int(stmt, 2);  
  81.         int age_type = sqlite3_column_type(stmt, 2);  
  82.           
  83.         const char *col_1_name = sqlite3_column_name(stmt, 1);  
  84.         char name[80];  
  85.         strncpy(name, (const char *)sqlite3_column_text(stmt, 1), 80);  
  86.         int name_type = sqlite3_column_type(stmt, 1);  
  87.           
  88.         //打印结果  
  89.         printf("col_count: %d, %s = %d(%s), %s = %s(%s), %s = %d(%s)\n",   
  90.                col_count, col_0_name, id, col_types[id_type], col_1_name, name,  
  91.                col_types[name_type], col_2_name, age, col_types[age_type]);  
  92.     }  
  93.       
  94.     fprintf(stderr, "sqlite step exit with %d\n", ret);  
  95.     sqlite3_finalize(stmt);  
  96.     sqlite3_close(conn);  
  97.       
  98.     return 0;  
  99. }  


运行结果如下:

[plain] view plaincopy
  1. [carl@Fedora sqlite]$ g++ sqlite_test2.cpp -lsqlite3  
  2. [carl@Fedora sqlite]$ ./a.out   
  3. 打开数据库成功!!!  
  4. 数据库语句对象编译成功!!!  
  5. 数据库语句对象bind成功!!!  
  6. 列数:3    列名:id   id值:0   id类型:1  col_count: 3, id = 0(Interger), name = Carl(Text), age = 0(Interger)  
  7. 列数:3    列名:id   id值:1   id类型:1  col_count: 3, id = 1(Interger), name = Carl(Text), age = 1(Interger)  
  8. 列数:3    列名:id   id值:2   id类型:1  col_count: 3, id = 2(Interger), name = Carl(Text), age = 2(Interger)  
  9. 列数:3    列名:id   id值:3   id类型:1  col_count: 3, id = 3(Interger), name = Carl(Text), age = 3(Interger)  
  10. 列数:3    列名:id   id值:4   id类型:1  col_count: 3, id = 4(Interger), name = Carl(Text), age = 4(Interger)  
  11. 列数:3    列名:id   id值:5   id类型:1  col_count: 3, id = 5(Interger), name = Carl(Text), age = 5(Interger)  
  12. 列数:3    列名:id   id值:6   id类型:1  col_count: 3, id = 6(Interger), name = Carl(Text), age = 6(Interger)  
  13. 列数:3    列名:id   id值:7   id类型:1  col_count: 3, id = 7(Interger), name = Carl(Text), age = 7(Interger)  
  14. 列数:3    列名:id   id值:8   id类型:1  col_count: 3, id = 8(Interger), name = Carl(Text), age = 8(Interger)  
  15. 列数:3    列名:id   id值:9   id类型:1  col_count: 3, id = 9(Interger), name = Carl(Text), age = 9(Interger)  
  16. sqlite step exit with 101 //101意思为SQLITE_DONE  
  17. [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,经常会占用更多的空间。


水平有限,如果有朋友发现错误,欢迎留言交流。
转载请保留本文链接,如果觉得我的文章能帮到您,请顶一下。,谢谢。
摘自 :http://blog.csdn.net/wzzfeitian/article/details/7993686
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值