在这一部分我将展示一些简单的应用程序来说明SQLite的众多特性。这些应用程序将在下面的一些子部分中展示,让我们通过学习一个很简单的应用程序来开始我们SQLite大陆的探险吧。下面的例子展示了一个典型的SQLite应用程序。它是一个使用SQLite API来处理一个SQLite数据库文件的C程序。
这是一个典型的SQLite应用程序:
#include <stdio.h>
#include "sqlite3.h"
int main(void)
{
sqlite3* db = 0;
sqlite3_stmt* stmt = 0;
int retcode;
retcode = sqlite3_open("MyDB", &db);
if (retcode != SQLITE_OK){
sqlite3_close(db);
fprintf(stderr, "Could not open MyDB/n");
return retcode;
}
retcode = sqlite3_prepare(db, "select SID from Students order by SID", -1, &stmt, 0);
if (retcode != SQLITE_OK){
sqlite3_close(db);
fprintf(stderr, "Could not execute SELECT/n");
return retcode;
}
while (sqlite3_step(stmt) == SQLITE_ROW){
int i = sqlite3_column_int(stmt, 0);
printf("SID = %d/n", i);
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return SQLITE_OK;
}
你可以编译上面的例子并且执行它。在这个文档中显示的示例输出是在一个linux机器上获得的,但是这些例子能够在SQLite运行的其他的平台上工作。这些例子假定你已经准备了可执行的sqlite3,libsqlite3.so(windows上是sqlite3.dll而Mac OS X上是libsqlite3.dylib)共享库,和sqlite3.h接口定义文件。你可以从http://www.sqlite.org上获取这些源代码或二进制形式的文件。你会发现如果你将所有这三个(sqlite3, the shared library, 和sqlite3.h)和范例放在同一个目录下处理该范例会比较容易。
举个例子,假设你在一个Linux系统上,并且你将app1.c示例程序保存在libsqlite3.so , sqlite3和sqlite3.h同一个目录下。你能够通过执行这条命令编译文件:gcc app1.c -o ./app1 -lsqlite3 -L.
它将会在当前工作的目录下产生一个名为app1的二进制文件。你可以执行这个二进制文件来查看输出。
注:SQLite源代码和应用程序必须在同一个编译器下编译。
如果你已经将SQLite作为一个包安装了,或者如果你的操作系统预安装了SQlite,你可能需要使用一组不同的编译参数。例如,在Ubuntu上,你可以通过命令sudo aptitude install sqlite3 libsqlite3-dev安装SQLite,并且你可以使用命令cc app1.c -o ./app1 -lsqlite3来编译应用程序。因为在现行的Mac OS X版本中包含SQLite,上述的相同的编译命令也能工作。
这个应用程序打开了在当前工作目录下的MyDB数据库文件。这个数据库需要至少一个表,命名为Students;这个表必须至少有一个整型列名为SID。在下一个例子中,你将会学习如何在数据库中创建新的表,和如何在表中插入行(也被称为元组和记录),但是在目前,你可以使用这些命令创建并落户表:
如果你现在运行app1(在linux系统下要引入SQLite库,,你可能需要在LD_LIBRARY_PATH环境变量中加入你的工作目录名字,你将会看到下面的输出:
注:在Linux,Unix和Mac OS X中,在命令提示符中键入app1的名字时,你可能需要前缀./
应用程序首先做好准备工作,接着执行SQL语句:select SID from Students order by SID。然后它进阶到作为结果的行集,一个接一个的获取SID的值,并且打印各个值。最后关闭数据库。
SQLite是一个调用级别上的接口库,它能够嵌入到应用程序中。该库将所有的SQLite API函数实现为C函数。所有的API函数都是以sqlite3_前缀命名,并且在sqlite3.h中声明。在示例应用程序中使用了他们中的一部分,他们是sqlite3_open, sqlite3_prepare, sqlite3_step, sqlite3_column_int, sqlite3_finalize, 和 sqlite3_close。应用程序也采用了助记符常量,即用于API的返回比较值的SQLITE_OK 和 SQLITE_ROW。这些助记符在sqlite3.h中被定义。
1.1.1.1 sqlite3_open
通过执行sqlite3_open函数,应用程序经由SQLite库打开了一个到数据库文件的新连接。(该应用程序可能有其他到相同的或者不同的数据库的开放连接。SQLite清楚地处理这些连接,并且他们在SQLite注意前是相互间独立的)。如果文件还不存在,SQLite将自动的创建数据库文件。
注:在打开或创建一个文件时,SQLite遵守一个懒惰策略:知道该文件被阅读访问时才真正的打开或者创建。sqlite3_open函数经由一个形参(db,在前面的例子中)返回一个连接句柄(一个指向sqlite3类型的对象的指针),而句柄被用来支持在数据库连接(因为这次打开连接)上的进一步操作。句柄表示了这次连接的完整情况。
1.1.1.2 sqlite3_prepare
sqlite3_prepare函数编译了一个SQL语句,并且产生了一个等价的内部对象。这个对象在数据库文法中作为一个准备语句被普遍的提及,在SQLite中他被实现为一个字节编码程序。字节编码程序是在虚拟机或者解释器上运行的SQL语言的一个抽象表示。想要得到更多的信息,看后面的部分字节编码编程语言。在本书中,我将交替使用条件字节编码程序和准备语句。sqlite3_prepare函数经由一个形参(在前面例子中的stmt)返回一个状态句柄(指向sqlite3_stmt类型对象的指针),该句柄被用来支持进一步的操作来操纵准备状态。在这个示例程序中,我准备了select SID from Students order by SID语句作为stmt句柄。这个句柄动作起来就像一个开放的光标并且他被用来获取SELECT语句返回的作为结果的行集,一次一行。
1.1.1.3 sqlite3_step
sqlite3_step函数将执行字节编码程序直到它遇到折点(因为它已经计算了新的一行),或者直到它停止(没有剩下的行了)。在之前的例子中,他返回了SQLITE_ROW,而在之后的例子中是SQLITE_DONE。因为有的SQL语句不返回行(例如UPDATE,INSERT,DELETE,和CREATE),当没有行要处理时,他总是返回SQLITE_DONE。Step函数移动指针的位置来获得SELECT语句的结果。初始的,指针指向输出行集的第一行的前一位置。执行一次step函数,指针移动到了输出行集的下一行。该指针只能向前移动。
1.1.1.4 sqlite3_column_int
如果step函数返回了SQLITE_ROW,你能够通过执行sqlite3_column_*API函数来检索每一列(也被认为是属性或域)的值。SQL/SQLite和C语言中的阻抗(数据类型)的不匹配能够被自动的处理:API在两种语言间,将数据进行从存储类型到请求类型的转换。在示例应用中,每个输出行是一个整型值,我们通过执行返回整型值的sqlite3_column_int函数来读取的SID的值。
1.1.1.5 sqlite3_finalize
sqlite3_finalize函数销毁准备好的状态。也就是说,擦除字节编码程序,并且释放分配给状态句柄的所有资源。句柄变为不可用。
1.1.1.6 sqlite3_close
sqlite3_close函数关闭数据库连接,并且释放了分配给该连接的所有资源。该连接句柄变为不可用。
1.1.1.7 其他有用的函数
其它被广泛使用的API是sqlite3_bind_*和sqlite3_reset。在一个SQL语句字符串(输入到sqlite3_prepare),一个或者多个文本值能够被SQL参数标识?(或者?NNN,:AAA,@AAA或者$AAA,其中NNN是一个数字,而AAA是一个标示符)来代替。他们成为准备语句的输入参数这些参数的值可以通过使用bind API函数来设置。如果一个参数没有值约束,那么它不是取默认值,就是在没有默认值被声明的时候取SQL NULL。reset API函数通过一个异常将状态句柄(例如,准备状态)重置回它的初始状态:所有有制约值的参数保持他们的原值。状态准备被应用程序再一次的执行,并且在再执行过程中重用这些值。然而,应用程序可能会在它开始重新执行的前再一次的执行bind API获得新值来代替前值。
1.1.1.8 返回值
所有的API函数返回0或者负整数值。SQLite推荐使用助记符来核对返回值。返回值SQLITE_OK表示成功。SQLITE_ROW表示sqlite3_step函数在SELECT语句返回的行集中找到了新的一行;SQLITE_DONE表示语句执行完成了。