SQLite核心源代码由C语言写就,同时提供了很多的扩展包可应用于其他编程语言和类库,如Python、Ruby、Java、Perl、.Net/C#、Qt和ODBC。在很多情况下,针对一种语言有很多扩展包可供选择,诸多的扩展包为不同的程序员满足不同的需求而设计开发。

由于笔者目前所做的项目和嵌入式Linux开发相关,所以本文从C语言的角度对SQLite的api进行探索和实践,先来简要介绍C/C++ 接口函数概述,然后结合代码在实践中对该部分内容进行总结。

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,定义如下:

严格地说,SQL预处理语句对象不是必需的,因为有使用方便的包装函数sqlite3_exec或sqlite3_get_table,它们封装并且隐藏了SQL语句对象。不过理解SQL语句对象能更好地使用SQLite。

关于C/C++ 接口函数更详细的部分本文不再赘述,请参考官方文件 An Introduction To The SQLite C/C++ Interface

代码实践

以下为具体的实践代码,相关总结与心得以注释的形式插入在代码,在执行代码前,请先下载SQLite源码并存储在同一路径下,按照以下方式执行编译即可:(也可将sqlite3编译成函数库再调用,具体请参照笔者另一篇文章sqlite 安装与编译)

具体实践代码如下: 

  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 }
12-17 23:26