转载

SQLite C/C++接口简介

翻译自 https://www.sqlite.org/cintro.html ,建议阅读原文

摘要

接下来的两个对象和八个方法包含了SQLite接口的基本要素:

  • sqlite3 数据库连接对象. 由sqlite3_open()创建,由sqlite3_close()销毁。
  • sqlite3_stmt 预编译语句对象. 由 sqlite3_prepare() 创建,由 sqlite3_finalize() 销毁。
  • sqlite3_open() 打开已存在或者新建数据库的连接。 sqlite3 的构造函数。
  • sqlite3_prepare() 将SQL文本编译成字节码,以便于执行查询或者更新数据库的操作 sqlite3_stmt 的构造函数。
  • sqlite3_bind() 将应用程序的数据与原始SQL中的 参数 绑定
  • sqlite3_step() 执行 sqlite3_stmt 到下一个结果或者结束
  • sqlite3_column() 当前结果行所在的列值
  • sqlite3_finalize() sqlite3_stmt 的析构函数。
  • sqlite3_close() sqlite3 的析构函数。
  • sqlite3_exec() 一个包装函数,为一条或多条SQL语句包装了 sqlite3_prepare() , sqlite3_step() , sqlite3_column() , 和 sqlite3_finalize() 。

简介

早期的SQLite只支持五个C/C++接口,所以非常容易学习。但是随着SQLite的不断壮大,新的C/C++接口不断加入,目前已有超过200个不同的接口。这能轻易压倒一个新手程序员。幸运的是,大部分SQLite的C/C++接口非常专业并且你不需要去关心。尽管有如此多的切入点,SQLite的核心API依然比较简单易于学习,易于编程。这篇文章旨在提供所有必需的背景信息以便于让你理解SQLite是如何工作的。

这份单独的文档, SQLite C/C++接口 ,提供了所有SQLite C/C++ 接口的详细说明。当读者理解了SQLite操作的基本原则,这份文档可以作为参考指南使用。本文章目的仅仅是介绍,而不是SQLite API 的完整或者权威的指南。

核心对象和接口

SQL数据库引擎的主要任务是执行SQL语句。为了实现这个目的,开发者需要知道这两个对象:

  • 数据库连接 对象:sqlite3
  • 预编译语句 对象:sqlite3_stmt

严格得讲,有了便捷的包装接口预编译语句对象,sqlite3_exec 或者 sqlite3_get_table之后, 预编译语句 对象不再是必须的。因为可以使用这些便捷的包装器封装和隐藏 预编译语句 对象。但是要充分利用SQLite需要理解预编译语句对象。

数据库连接 和 预编译语句 对象是由以下列出的一部分接口控制:

  • sqlite3_open()
  • sqlite3_prepare()
  • sqlite3_step()
  • sqlite3_column()
  • sqlite3_finalize()
  • sqlite3_close()

这六个C/C++接口程序和上述的两个对象来自于SQLite基础功能的核心。理解了它们,开发者将能更好得使用SQLite。

请注意上述的程序是概念性的而不是实际上的。这些程序大都存在多个版本。比如上面列表只显示了单个名为 sqlite3_open() 的程序,但实际上有三个独立的程序以不同的方式完成同样的事情: sqlite3_open() , sqlite3_open16() 和 sqlite3_open_v2() 。另外列表里还提及了 sqlite3_column() ,但实际上并没有这样的程序存在。列表中显示的"sqlite3_column()"代表的是这个程序整个家族,它们被用于提取不同类型的列数据。

这里总结一下核心接口会做什么:

  • sqlite3_open() 用来打开一个数据库文件的连接并返回数据库连接对象。这通常是应用调用的第一个SQLite API,低于大多数其他的SQLite API这是先决条件。许多SQLite接口需要一个指向数据库连接的指针作为第一个参数,也可以认为是数据库连接对象的方法。sqlite3_open()是数据库连接对象的构造方法。

  • sqlite3_prepare() 将SQ文本转换为预编译语句对象并返回该对象的指针。这个接口需要一个由sqlite3_open()创建的指向数据库连接的指针和一段包含SQL语句的文本。这个API并非真正得执行SQL语句,仅仅准备需要执的SQL语句。

    把每条SQL语句想象成一个小的计算机程序。sqlite3_prepare()的目的是将程序编译成目标代码。预编译语句是目标代码。接着sqlite3_step()接口运行目标代码并得到结果。

请注意对于新的应用不建议使用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()"家族,用于返回不同数据类型的结果。在这个家族里也有函数用来返回结果的大小(如果类型是string或者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()创建的数据库连接。在关闭连接之前,所有的预编译语句都应该被finalize。

核心程序和接口的典型用法

应用若要使用SQLite通常的做法是在初始化的时候通过sqlite3_open()创建单个数据库连接。注意sqlite3_open()可以用来打开存在的数据库文件也能创建新的数据库文件。尽管很多的应用仅仅使用单个数据库连接时,但也没有任何理由不能多次调用 sqlite3_open()创建多个数据库连接,同一个数据库或者不同的数据库。多线程的应有时会为每个线程创建不同的数据库连接。还要注意,没有必要为了访问两个或者多个数据库而创建不同的数据库连接。单个数据库连接可以使用 ATTACH SQL命令同时访问两个或者多个数据库。

大多数应用的做法是在关闭时调用sqlite3_close()销毁数据库连接。或者例如一个应用使用SQLite作为文件格式,在文件/打开菜单操作时打开数据库连接,在文件/关闭菜单时销毁相应的数据库连接。

若要运行SQL语句,请遵循以下步骤:

  • 使用 sqlite3_prepare() .创建预编译语句对象。
  • 调用 sqlite3_step() 一次或者多次执行预编译语句对象
  • 对于查询来说,调用 sqlite3_column() 提取执行 sqlite3_step() 得到的结果集
  • 使用 sqlite3_finalize() 来销毁预编译语句

为了更加有效得使用SQLite,以上是需要了解的。剩下的就只有细枝末节。

方便的包装器

sqlite3_exec() 接口是一个方便的包装器,调用一个方法便可执行上面的四个步骤。传递到 sqlite3_exec() 中的回调函数将用于处理每行结果集。 sqlite3_get_table() 是另一个方便的包装器,同样可以用上述的四个步骤。与 sqlite3_exec() 不同的是, sqlite3_get_table() 将结果存储在堆存储器里而非调用回调函数。

无论是 sqlite3_exec() 还是 sqlite3_get_table() 做的任何事情都可以由核心程序来完成,认识到这一点很重要。事实上,这些包装器仅仅实现了核心程序。

绑定参数与重用预编译语句

在之前的讨论中,假设了每条SQL语句只准备,执行了一次然后销毁。但是SQLite允许相同的预编译语句执行多次。这由以下的程序完成:

  • sqlite3_reset()
  • sqlite3_bind()

在 预编译语句 被一次或多次调用 sqlite3_step() 执行之后,它可以通过调用 sqlite3_reset() 重置以便于再次执行。对已存在的预编译语句对象使用 sqlite3_reset() 而不是创建一个新的预编译语句,避免不必要得调用 sqlite3_prepare() 。对于很多SQL语句来说,执行sqlite3_prepare()的时间等于或者超过执行sqlite3_step()的时间。所以避免调用sqlite3_prepare()可以显著提升性能。

通常情况下,尽管多次执行相同的SQL语句并非有用。更多时候,执行的是相似的语句。比如你可能想要多次执行一条插入语句,但插入的值不同。为了使用这类的灵活性,SQLite允许将要执行的SQL语句包含之前绑定的参数。这些值可以在后面更改,这样相同的预编译语句可以使用新的值执行第二次。

在SQLite中,无论是否有效得包含字符串,都可以选取以下的形式作为参数:

  • ?
  • ?NNN
  • :AAA
  • $AAA
  • @AAA

在上面的例子中,NNN是整数值,AAA是标识符。参数初始化值为NULL。首先先调用 sqlite3_step() 或者在 sqlite3_reset() 立即调用。应用可以调用其中一个sqlite3_bind()接口附加到参数上。每次调用 sqlite3_bind() 将覆盖先前的参数绑定。

应用程序可以提前准备多条SQL语句,并根据需要对其执行。对于准备的语句在数量上没有任何限制。

配置SQLite

对于大多数应用来说SQLite的默认配置已经足够了。但是有时开发者想要调整设,以尽量提升一点性能,或者使用一些不起眼的特性。

sqlite3_config() 接口用于创建SQLite全局的,进程级的配置更改。在任何数据库连接被创建前,sqlite3_config()接口必须被调用。 sqlite3_config() 接口允许程序员做这样的事情:

  • 调整SQLite内存分配,包括为实时嵌入系统设置内存分配器和设置应用定义的 内存分配器 。
  • 设置进程级的 错误日志
  • 指定应用定义的页面缓存
  • 调整互斥体使之适合于不同的 线程模型 ,或者替换应用定义的互斥系统
    进程级的配置完成之后 数据库连接 便会建立。个别的数据库连接可以调用 sqlite3_limit() 和 sqlite3_db_config() 进行配置。

扩展SQLite

SQLite还包括了用来扩展功能的接口,这些程序包括:

  • sqlite3_create_collation()
  • sqlite3_create_function()
  • sqlite3_create_module()
  • sqlite3_vfs_register()

sqlite3_create_collation()接口用来为排序文本创建新的排序序列。 sqlite3_create_module() 接口用来注册新的 虚拟表 实现。 sqlite3_vfs_register( )接口创建新的 VFSes 。

sqlite3_create_function() 接口创建新的SQL功能 - 无论是标量还是聚合。新功能的实现通常使用了以下几个附加接口:

  • sqlite3_aggregate_context()
  • sqlite3_result()
  • sqlite3_user_data()
  • sqlite3_value()

SQLite所有内置的SQL函数正式使用这些接口来创建的。参考SQLite源码,特别是date.c和func.c源文件的例子。

共享的库或 Dll 可以用作 SQLite 的 可加载扩展 。

其他接口

这篇文章仅仅提及了SQLite接口的基础功能。SQLite库还包含了很多其他有用的特性但是这里没有描述。你能在 C/C++接口规范 中找到SQLite完整的功能列表。请参阅关于SQLite所有接口的权威文档。

正文到此结束
Loading...