SQLite接口函数 - C核心api实践与总结
SQLite核心源代码由C语言写就,同时提供了很多的扩展包可应用于其他编程语言和类库,如Python、Ruby、Java、Perl、.Net/C#、Qt和ODBC。在很多情况下,针对一种语言有很多扩展包可供选择,诸多的扩展包为不同的程序员满足不同的需求而设计开发。
由于笔者目前从事嵌入式开发相关的工作,所以从C语言的角度对SQLite的api进行探索和实践,本文主要从实例出发,结合代码在实践中学习与理解C API的使用,关于C/C++ 接口函数更细节的部分本文不再详细赘述,请具体请参考官方文件 An Introduction To The SQLite C/C++ Interface或者《SQLite 权威指南》。
C/C++ 接口函数概述
数据库连接对象和SQL语句对象由下面几个核心的C/C++接口来控制:sqlite3_open()、sqlite3_prepare()、sqlite3_step()、sqlite3_column()、sqlite3_finalize()、sqlite3_close()。
使用SQLite3时根据以上函数大概分为几个过程,这几个过程是概念上的说法,而不完全是程序运行的过程,如sqlite3_column()表示的是对查询获得一行里面的数据的列的各个操作统称,实际上在sqlite中并不存在这个函数。在SQLite提供的C/C++接口中,其中5个API属于核心接口。相比于其它数据库引擎提供的API,如OCI、MySQL API等,SQLite提供的接口易于理解和掌握。
以上六个C/C++接口及上面的两个对象构成SQLite的核心功能。注意这些接口有些有多个版本,例如sqlite3_open()有三个独立的版本:sqlite3_open(), sqlite3_open16()和sqlite3_open_v2(),它们以稍微不同的方式完成同样的事情。sqlite3_column()代表一个家族系列:sqlite_column_int(), sqlite_column_blob()等等,用于提取结果集中各种类型的列数据。
一个SQL数据库引擎的首要任务是执行SQL语句以获得我们想要的数据。为了完成这个任务,开发需要知道两个对象:数据库连接对象sqlite3和SQL预处理语句对象sqlite3_stmt,定义如下:
typedef struct sqlite3 sqlite3;
typedef struct sqlite3_stmt sqlite3_stmt;
严格地说,SQL预处理语句对象不是必需的,因为有使用方便的包装函数sqlite3_exec或sqlite3_get_table,它们封装并且隐藏了SQL语句对象。不过理解SQL语句对象能更好地使用SQLite。
代码实践
以下为具体的实践代码,相关总结与心得以注释的形式插入在代码,在执行代码前,请先下载SQLite源码并存储在同一路径下,按照以下方式执行编译即可:(也可将sqlite3编译成函数库再调用,具体请参照笔者另一篇文章sqlite 安装与编译)
gcc sqlite3.c test_api.c -lpthread -ldl -o testapi -I.
具体实践代码如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sqlite3.h> 5 6 int main( int argc, char **argv ) 7 { 8 sqlite3 *db; 9 sqlite3_stmt * stmt; 10 const char *zTail; 11 int rc = -1; 12 char *sql; 13 14 /*1. 连接数据库*/ 15 /*int sqlite3_open( 16 *const char *filename, // 数据库文件名 (UTF-8) 17 *sqlite3 **ppDb, // OUT: SQLite数据库句柄 18 *int flags, // 数据库文件操作标志 19 *const char *zVfs // 用于重写默认操作系统接口sqlite3_vfs的方法 20 *); 21 */ 22 rc = sqlite3_open_v2("mysqlite.db", &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL); 23 if(rc != SQLITE_OK){ 24 printf("%s\n", sqlite3_errmsg(db)); 25 } 26 27 /*2. 创建Table*/ 28 /*sqlite3_prepare_v2()将SQL语句编译为sqlite内部一个结构体(sqlite3_stmt), 29 *该结构体中包含了将要执行的SQL语句的信息 30 *第四个参数用来指向输入参数中下一个需要编译的SQL语句存的 SQLite statement 对象的指针 31 *注意现在sqlite3_prepare()已经不被推荐使用了,目前官司方推荐使用sqlite3_prepare_v2() 32 *SQLITE_API int sqlite3_prepare_v2( 33 *sqlite3 *db, // SQLite数据库句柄 34 *const char *zSql, // SQL 语句, UTF-8 编码 35 *int nByte, // zSql的字节长度 36 *sqlite3_stmt **ppStmt, // OUT: sql语句句柄(statement handle) 37 *const char **pzTail // OUT: 指向zSql未使用的部分 38 *); 39 */ 40 sql = "CREATE TABLE players ( \n\ 41 id INTEGER PRIMARY KEY, \n\ 42 name TEXT, \n\ 43 age INTEGER);"; 44 rc = sqlite3_prepare_v2(db, sql, -1, &stmt, &zTail); 45 if(rc != SQLITE_OK){ 46 printf("%s\n", sqlite3_errmsg(db)); 47 } 48 49 /*调用sqlite3_step(),此时SQL语句才真正执行,执行成功,返回SQLITE_DONE或SQLITE_ROW. 50 *每次调用sqlite3_step(),只返回一行数据,使用sqlite3_column_XXX()函数来取出这些数据 51 *要取出全部的数据,则需要反复调用sqlite3_step() 52 */ 53 rc = sqlite3_step(stmt); 54 if(rc != SQLITE_DONE){ 55 printf("%s\n", sqlite3_errmsg(db)); 56 } 57 58 /*调用sqlite3_finalize(),释放stmt占用的内存,该内存是在sqlite3_prepare()时分配的 59 *如果SQL语句要重复使用,可以调用sqlite3_reset()来清除已经绑定的参数 60 */ 61 rc = sqlite3_finalize(stmt); 62 if(rc != SQLITE_OK){ 63 printf("%s\n", sqlite3_errmsg(db)); 64 } 65 66 /*3.1 插入数据*/ 67 sql = "INSERT INTO players (name,age) VALUES(?,?);"; 68 rc = sqlite3_prepare_v2(db, sql, -1, &stmt, &zTail); 69 if(rc != SQLITE_OK){ 70 printf("%s\n", sqlite3_errmsg(db)); 71 } 72 73 /*sqlite3_bind_xxx的第四个参数为负,则字符串长度由第一个0终的位数决定 74 *SQLITE_STATIC表示命令执行完后的信息为static类型,不能被改动,而且不需要被free 75 */ 76 char str[] = "Kevin"; 77 int n = 23; 78 sqlite3_bind_text(stmt,1,str,-1,SQLITE_STATIC); 79 sqlite3_bind_int(stmt,2,n); 80 rc = sqlite3_step(stmt); 81 if( rc != SQLITE_DONE){ 82 printf("%s",sqlite3_errmsg(db)); 83 } 84 85 //清除已经绑定的参数 86 sqlite3_reset(stmt); 87 //插入第二个数据 88 char str2[] = "Jack"; 89 int n2 = 16; 90 sqlite3_bind_text(stmt,1,str2,-1,SQLITE_STATIC); 91 sqlite3_bind_int(stmt,2,n2); 92 rc = sqlite3_step(stmt); 93 if( rc != SQLITE_DONE){ 94 printf("%s",sqlite3_errmsg(db)); 95 } 96 sqlite3_finalize(stmt); //释放stmt所占的内存 97 98 /*3.2 插入数据*/ 99 char **pz_err_msg = NULL; 100 sql = "INSERT INTO players(name, age) VALUES('Rose', 24);"; 101 rc = sqlite3_exec(db, sql, NULL, NULL, pz_err_msg); 102 if (SQLITE_OK != rc) { 103 printf("%s:sqlite3_exec insert \"%s\" failed\n", __FUNCTION__, sql); 104 if (NULL != pz_err_msg) { 105 printf("%s: error: %s\n", __FUNCTION__, *pz_err_msg); 106 sqlite3_free(pz_err_msg); 107 pz_err_msg = NULL; 108 } 109 } 110 111 /*4. 查询所有数据*/ 112 sql = "SELECT id, name, age FROM players ORDER BY age"; 113 rc = sqlite3_prepare_v2(db, sql, -1, &stmt, &zTail); 114 if(rc != SQLITE_OK){ 115 printf("%s\n", sqlite3_errmsg(db)); 116 } 117 118 int number, id; 119 const unsigned char * name; 120 /* 121 ** 执行SQL语句之后会,sqlite3_step()会返回不同的参数,如[SQLITE_BUSY],[SQLITE_DONE], 122 ** [SQLITE_ROW], [SQLITE_ERROR], [SQLITE_MISUSE]. 123 ** 当该函数完成一次类似查询(select)的SQL语句执行后,将返回[SQLITE_ROW],每执行一次 124 ** sqlite3_step(),都将准备好一行新的查询数据结果,该结果可通过sqlite3_column()系列函 125 ** 数获取;要查询下一行的数据,只需重复执行sqlite3_step()即可。 126 */ 127 rc = sqlite3_step(stmt); 128 while( rc == SQLITE_ROW ){ 129 id = sqlite3_column_int( stmt, 0 ); //该函数用于获取当前行指定列(id)的数据(int类型) 130 name = sqlite3_column_text( stmt, 1 ); 131 number = sqlite3_column_int( stmt, 2 ); 132 printf("ID: %d Name: %s Age: %d \n",id,name,number); 133 sleep(1); 134 rc = sqlite3_step(stmt); 135 } 136 rc = sqlite3_finalize(stmt); 137 if(rc != SQLITE_OK){ 138 printf("%s\n", sqlite3_errmsg(db)); 139 } 140 141 /*5. 删除数据*/ 142 sql = "DELETE FROM players WHERE age < 24;"; 143 rc = sqlite3_exec(db, sql, NULL, NULL, pz_err_msg); 144 if (SQLITE_OK != rc) { 145 printf("%s:sqlite3_exec insert \"%s\" failed\n", __FUNCTION__, sql); 146 if (NULL != pz_err_msg) { 147 printf("%s: error: %s\n", __FUNCTION__, *pz_err_msg); 148 sqlite3_free(pz_err_msg); 149 pz_err_msg = NULL; 150 } 151 } 152 153 /*6. 查询所有数据2*/ 154 int nrow = 0, ncol = 0; 155 int i, j; 156 char **result; 157 sql = "SELECT id, age, name FROM players;"; 158 rc = sqlite3_get_table(db, sql, &result, &nrow, &ncol, pz_err_msg); 159 if (SQLITE_OK != rc) 160 { 161 printf("%s:sqlite3_get_table \"%s\" failed\n", __FUNCTION__, sql); 162 if (NULL != pz_err_msg) 163 { 164 printf("%s: error: %s\n", __FUNCTION__, *pz_err_msg); 165 sqlite3_free(pz_err_msg); 166 pz_err_msg = NULL; 167 } 168 } 169 for(i=0; i < nrow+1; i++) { 170 for(j=0; j < ncol; j++) { 171 printf("%s ", result[i * ncol + j]); 172 } 173 printf("\n"); 174 } 175 176 /*5. 关闭数据库*/ 177 sqlite3_close(db); 178 return 0; 179 }