其实看上一篇的示例代码,90%的场景就够用了。这里是对官方接口文档介绍部分的大致翻译,有些比如大量重复语句执行的性能优化,后面有机会用到了,再做深入探索。
2.1 核心对象和接口
要想用的好,还是要学习点基本知识。虽然枯燥,但是还是要学的。SQLite 有很多API,先从常用的开始,其它的根据需要学习。
SQL 数据库 引擎的主要任务是计算 SQL 语句。为此,需要两个对象:
- 数据库连接 对象:对应 sqlite3
- 预处理语句 对象:对应 sqlite3_stmt
当使用一些便利的拓展封装的接口时,比如:sqlite3_exec or sqlite3_get_table ,预处理语句不是必须要了解的。但是,要充分用好 SQLite,还是需要理解预处理语句的。
预处理语句:
在数据库编程中,预处理语句是一种预编译的SQL语句,其中的参数在执行时被值替换,而不是作为语句本身的一部分。用于执行重复性高的数据库操作。通过预处理语句,可以提高数据库操作的效率和安全性。
使用以下接口,来对 数据库连接 和 预处理语句 进行控制:
- sqlite3_open()
- sqlite3_prepare()
- sqlite3_step()
- sqlite3_column()
- sqlite3_finalize()
- sqlite3_close()
上面这些控制语句只是概念示例,有些具有很多版本,有些甚至不存在。以下是对这些核心接口的功能说明:
- sqlite3_open()
打开数据库文件,返回一个数据库连接对象。这通常是第一个被调用的接口,也是调用其它接口的前提。很多接口以数据库连接对象的指针,作为第一个参数。其实可以认为是这些方法是数据库连接对象的方法,而这个open方法就是数据库连接对象的构造函数。 - sqlite3_prepare()
这个例程将SQL文本转换为准备好的语句对象,并返回指向该对象的指针。这个接口需要一个数据库连接指针,该指针是由先前调用sqlite3_open()创建的,并且需要一个包含要准备的SQL语句的文本字符串。这个API实际上并不计算SQL语句。它只是为求值准备SQL语句。
把每个SQL语句看作一个小的计算机程序。(这么说来,这种玩法跟 GPU 和 渲染领域 有某种类似的思想的感觉呢。使用一种脚本语言,编译一下,扔给一个叫做引擎的东西去运行。)sqlite3_prepare()的目的是将该程序编译成目标代码。准备好的语句是目标代码。然后sqlite3_step()接口运行对象代码以获得结果。
新的应用程序应该总是调用sqlite3_prepare_v2()而不是sqlite3_prepare()。为了向后兼容,保留了旧的sqlite3_prepare()。但是sqlite3_prepare_v2()提供了一个更好的接口。 - sqlite3_step()
这个例程用于计算先前由sqlite3_prepare()接口创建的预处理语句。该语句的求值直到第一行结果可用为止。为了进一步到第二行结果,再次调用sqlite3_step()。继续调用sqlite3_step(),直到语句完成。不返回结果的语句(例如:INSERT、UPDATE或DELETE语句)只需要调用sqlite3_step()就可以完成。 - sqlite3_column()
这个例程从sqlite3_step()求值的预处理语句的结果集的当前行返回一列。每次sqlite3_step()停止并得到一个新的结果集行时,可以多次调用这个例程来查找该行中所有列的值。
如上所述,在SQLite API中确实没有所谓的“sqlite3_column()”函数。相反,我们这里所说的“sqlite3_column()”是代表了整个函数族,这些函数从各种数据类型的结果集中返回一个值。这个系列中还有一些例程返回结果的大小(如果它是字符串或BLOB)和结果集中的列数。- sqlite3_column_blob()
- sqlite3_column_bytes()
- sqlite3_column_bytes16()
- sqlite3_column_count()
- sqlite3_column_double()
- sqlite3_column_int()
- sqlite3_column_int64()
- sqlite3_column_text()
- sqlite3_column_text16()
- sqlite3_column_type()
- sqlite3_column_value()
- sqlite3_finalize()
这个例程销毁由先前调用sqlite3_prepare()创建的预处理语句。为了避免内存泄漏,必须使用对这个例程的调用来销毁每个准备好的语句 - sqlite3_close()
这个例程关闭先前通过调用sqlite3_open()打开的数据库连接。在关闭连接之前,应该完成与连接相关的所有预处理语句。
2.3 核心例程和对象的典型用法
应用程序通常会在初始化期间使用sqlite3_open()来创建单个数据库连接。注意,sqlite3_open()既可以用来打开现有的数据库文件,也可以用来创建和打开新的数据库文件。虽然许多应用程序只使用单个数据库连接,但应用程序没有理由不能多次调用sqlite3_open()来打开多个数据库连接——无论是到相同的数据库还是到不同的数据库。有时,多线程应用程序将为每个线程创建单独的数据库连接。注意,单个数据库连接可以使用ATTACH SQL命令访问两个或更多数据库,因此没有必要为每个数据库文件建立单独的数据库连接。
许多应用程序在关闭时通过调用sqlite3_close()来销毁它们的数据库连接。或者,例如,使用SQLite作为其应用程序文件格式的应用程序可能在响应file / open菜单操作时打开数据库连接,然后在响应file /Close菜单时销毁相应的数据库连接。
要运行SQL语句,应用程序需要遵循以下步骤:
1. 使用sqlite3_prepare()创建一个准备好的语句。
2. 通过一次或多次调用sqlite3_step()来计算准备好的语句。
3. 对于查询,在两次调用sqlite3_step()之间调用sqlite3_column()来提取结果。
4. 使用sqlite3_finalize()销毁准备好的语句。
为了有效地使用SQLite,上述内容是我们真正需要知道的。剩下的就是优化和细节了。
2.4 围绕核心例程的便利包装
sqlite3_exec()接口是一个方便的包装器,它通过一个函数调用执行上述所有四个步骤。传递给sqlite3_exec()的回调函数用于处理结果集的每一行。sqlite3_get_table()是另一个方便的包装器,它完成上述所有四个步骤。sqlite3_get_table()接口与sqlite3_exec()的不同之处在于,它将查询结果存储在堆内存中,而不是调用回调。
重要的是要认识到,sqlite3_exec()和sqlite3_get_table()都不能做任何使用核心例程无法完成的事情。实际上,这些包装器完全是根据核心例程实现的。
2.5 绑定参数和重用预处理语句
在前面的讨论中,假设每个SQL语句只准备一次,然后求值,然后销毁。然而,SQLite允许对相同的预处理语句进行多次求值。这是使用以下例程完成的:
-
sqlite3_reset()
-
sqlite3_bind()
在通过一次或多次调用sqlite3_step()对准备好的语句求值之后,它可以被重置,以便通过调用sqlite3_reset()再次求值。可以把sqlite3_reset()看作是将准备好的语句程序倒回开始。在现有的预处理语句上使用sqlite3_reset()而不是创建一个新的预处理语句,可以避免不必要地调用sqlite3_prepare()。对于许多SQL语句,运行sqlite3_prepare()所需的时间等于或超过运行sqlite3_step()所需的时间。因此,避免调用sqlite3_prepare()可以显著提高性能。
多次计算完全相同的SQL语句通常是没有用处的。更常见的是,人们想要评估类似的陈述。例如,您可能希望使用不同的值对INSERT语句进行多次求值。或者,您可能希望在WHERE子句中使用不同的键多次计算相同的查询。为了适应这一点,SQLite允许SQL语句包含在求值之前“绑定”到值的参数。稍后可以更改这些值,并且可以使用新值第二次计算相同的预处理语句。只要查询或数据修改语句中允许使用字符串文字、blob文字、数字常量或NULL, SQLite就允许使用参数。(DQL或DML)(参数不能用于列名或表名,也不能用作约束或默认值的值。参数采用下列形式之一:
-
?
-
? NNN
-
: AAA
-
$ AAA
-
@ AAA
在上面的例子中,NNN是一个整数值,AAA是一个标识符。参数初始值为NULL。在第一次调用sqlite3_step()之前或在sqlite3_reset()之后,应用程序可以调用sqlite3_bind()接口将值附加到参数上。每次调用sqlite3_bind()都会覆盖先前对同一参数的绑定。
允许应用程序提前准备多个SQL语句,并根据需要对它们进行求值。未完成的预处理语句的数量没有任意限制。一些应用程序在启动时多次调用sqlite3_prepare()来创建它们需要的所有预处理语句。其他应用程序保留最近使用的预处理语句的缓存,然后在可用时重用缓存的预处理语句。另一种方法是仅在循环内部重用预处理语句。
2.6 配置SQLite
SQLite的默认配置适用于大多数应用程序。但有时开发人员想要调整设置,试图挤出更多的性能,或利用一些模糊的功能。
sqlite3_config()接口用于对SQLite进行全局的、进程范围的配置更改。在创建任何数据库连接之前,必须调用sqlite3_config()接口。sqlite3_config()接口允许程序员做这样的事情:
- 调整SQLite如何分配内存,包括设置适合安全关键型实时嵌入式系统和应用程序定义的内存分配器的替代内存分配器。
- 设置进程范围的错误日志。
- 指定应用程序定义的页面缓存。
- 调整互斥锁的使用,使其适合于各种线程模型,或者替换一个应用程序定义的互斥锁系统。
在完成进程范围的配置并创建数据库连接之后,可以使用调用sqlite3_limit()和sqlite3_db_config()来配置各个数据库连接。
2.7 拓展SQLite
SQLite包含可用于扩展其功能的接口。这些例程包括:
- sqlite3_create_collation ()
- sqlite3_create_function ()
- sqlite3_create_module ()
- sqlite3_vfs_register ()
sqlite3_create_collation()接口用于为文本排序创建新的排序序列。sqlite3_create_module()接口用于注册新的虚拟表实现。sqlite3_vfs_register()接口创建新的虚拟存储系统。
sqlite3_create_function()接口创建新的SQL函数——可以是标量函数,也可以是聚合函数。新的函数实现通常使用以下附加接口: - sqlite3_aggregate_context()
- sqlite3_result()
- sqlite3_user_data()
- sqlite3_value()
SQLite的所有内置SQL函数都是使用完全相同的接口创建的。参考SQLite源代码,特别是date.c和function .c源文件以获取示例。
共享库或dll可以用作SQLite的可加载扩展。
2.8 其它接口
本文只提到最重要和最常用的SQLite接口。SQLite库包括许多其他api,它们实现了这里没有描述的有用特性。形成SQLite应用程序编程接口的完整函数列表可以在 C/C++ Interface Specification 中找到。有关所有SQLite接口的完整和权威信息,请参考该文档。
1245

被折叠的 条评论
为什么被折叠?



