SQLite 中 C/C++ 接口介紹
這篇文章簡要的介紹了 SQLite 的 C/C++ 接口。
早期版本的 SQLite 很好學是因為他們只提供了 5 個 C/C++ 的接口。但是隨著 SQLite 功能的增加,新的 C/C++ 接口加入,現在已經有超過 200 個不同的 API 了。這對新人可能是一種阻礙。幸運的是,大部分的 C/C++ 接口都是有特殊用途的,不需要了解。盡管有這么多的入口點,核心的 API 還是相當的簡單而且容易使用。這篇文章旨在提供所有能使讀者容易理解 SQLite 如何工作的背景信息。
一個獨立的接口文檔提供了 SQLite 不同的 C/C++ 接口的詳細說明。一旦讀者理解了操作 SQLite 的基本概念,該文檔就可以成為參考手冊了。這篇文章只是一個介紹,不會是 SQLite 的完整、權威的參考手冊。
1.0 核心對象和接口
SQL 數據庫引擎的核心任務是計算 SQL 語句的值(evaluate statements of SQL)。為了完成這個目的,開發者需要了解兩個對象:
數據庫連接對象(The database connection object):sqlite3
預處理好的語句對象(The prepared statement object): sqlite3_stmt
嚴格來講,對于一些封裝好的便捷接口 prepared statement object不是必須的,比如sqlite3_exec 還有 sqlite3_get_table, 在內部求值時都會封裝并隱藏這些 prepared statement object。然而,要想充分利用 SQLite, 理解 prepared statements 還是有必要的。
Database connection 和 prepared statement 對象由下面列出的一組 C/C++ 接口(interface routine)控制。
sqlite3_open() sqlite3_prepare() sqlite3_step() sqlite3_column() sqlite3_finalize() sqlite3_close()
上面列出的 6 個 C/C++ 接口還有兩個對象組成了 SQLite 的核心功能。理解了這些的開發者在使用 SQLite 時就會很容易了。
注意上面列出的這些接口只是一類接口而不是實際的接口。這些接口都有許多不同的版本。比如,上面列出的一個叫做 sqlite3_open() 的接口,事實上是由 3 個完全不同的接口組成的:sqlite3_open(), sqlite3_open16() 還有 sqlite3_open_v2()。上面列表中提到的sqlite3_column() 實際上并不存在。列表中提到的 “sqlite3_column()” 實際上是由一簇為了獲取不同列類型的接口組成。
下面是核心接口的簡要介紹:
sqlite3_open() 這個接口打開一個到 SQLite 數據庫文件的鏈接并返回一個數據庫連接對象。這通常是應用程序調用的第一個 SQLite 的 API,并且也是其他大部分的 SQLite API 所需要的。大部分的 SQLite 接口需要一個指向 database connection object 的指針作為第一個參數,可以認為是數據庫連接對象上的方法。這個接口是數據庫連接對象的構造器。
sqlite3_prepare() 這個接口將 SQL 語句轉換為一個 prepared statement 對象并返回指向這個對象的指針。這個接口需要之前使用 sqlite3_open() 返回的數據庫連接對象,還有一個包含 SQL 語句的文本字符串作為參數。這個 API 實際上并不執行 SQL 語句。它僅僅只是準備用于執行的 SQL 語句。把每個 SQL 語句想象成一個小型的計算機程序。sqlite3_prepare() 是為了把那個程序編譯成對象代碼(object code)。Prepared statement 就是這個對象代碼。之后 sqlite3_step() 運行這個對象代碼獲取結果。
注意對于新的程序已經不推薦使用 sqlite3_prepare()。新的應用推薦使用sqlite3_prepare_v2() 接口。
sqlite3_step() 這個接口用于執行之前用 sqlite3_prepare() 創建的 prepared statement。這個接口只返回結果集的第一條結果。為了獲取第二條結果,再調用一次sqlite3_step()。繼續調用 sqlite3_step() 直到語句結束。不返回結果的語句(比如:INSERT, UPDATE, 或者 DELETE 語句)調用一次 sqlite3_step() 就行了。
sqlite3_column() 這個接口返回使用 sqlite3_step() 查詢的 prepared statement 的結果集中當前行的某一列。每次調用完 sqlite3_step() 都會產生一個新的 result set row。這個接口可以被調用多次用于獲取一行中的不同列。正如上面所提到的,事實上在 SQLite 的 API 中并沒有 “sqlite3_column()” 這個函數。相反的,我們這里調用的 “sqlite3_column()” 是為了獲取某列中不同類型值的一簇的接口占位符(a place-holder for an entire family of functions)。這類接口中有返回結果大小(如果是字符串或者 BLOB,譯注:Binary Large OBject)還有結果集中列數的接口。
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() 創建的 prepared statement。為了避免內存泄露,必須這個接口銷毀之前創建的 prepared statement。
sqlite3_close() 這個接口關閉之前由調用 sqlite3_open() 創建的數據庫連接。在關閉數據庫連接前所有與之關聯的 prepared statements 都應該已經被銷毀了。
1.1 核心接口和對象的使用方法
一個想要使用 SQLite 的應用程序通常在初始化時使用 sqlite3_open() 創建一個數據庫連接。注意 sqlite3_open() 既可以用于打開一個現存的數據庫,也可以創建并打開一個新的數據庫。因為許多的應用程序只使用一個數據庫連接,所以就沒有理由讓一個應用程序多次調用sqlite3_open() 創建多個數據庫連接 – 同一個數據庫或者不同的數據庫。有時一個多線程的應用會為不同的線程創建獨立的數據庫連接。注意,為了訪問兩個或者多個數據庫也沒必要創建多個獨立的連接。一個單一的數據庫連接可以使用 ATTACH SQL 語句同時訪問兩個或者多個數據庫(譯注:http://sqlite.awardspace.info/syntax/sqlitepg12.htm)。
許多應用在關閉時調用 sqlite3_close() 銷毀它們的數據庫連接。比如,一個使用 SQLite 作為它的應用程序文件格式(application file format)會在點擊 文件/打開(File/Open) 菜單時創建一個數據庫連接,在點擊 文件/關閉 (File/Close) 菜單時關閉這個連接。
要執行 SQL 語句,程序需要遵循以下幾步:
使用 **sqlite3_prepare()** 創建一個 prepared statement。 通過一次或多次調用 **sqlite3_step()** 查詢 prepared statement 的結果。 對于查詢來說,在調用 **sqlite3_step()** 后通過調用 **sqlite3_column()** 獲取結果。 使用 **sqlite3_finalize()** 銷毀 prepared statement。
上述都是為了高效的使用 SQLite 讀者所需要知道的。其余的都只是補充和細節。
2.0 核心 API 的便捷封裝
sqlite3_exec() 是使用一次函數調用完成上述四種接口調用的便捷封裝。 sqlite3_exec()在處理結果集的每行時調用傳入的回調函數。sqlite3_get_table() 是另一個使用一次函數調用完成上述四種接口調用的便捷封裝。sqlite3_get_table() 與 sqlite3_exec() 的不同之處是將結果集保存在堆中而不是每次都調用回調函數。
需要注意的是 sqlite3_exec() 和 sqlite3_get_table() 都不能實現核心接口不能完成的事。事實上,這些封裝都是完全由核心接口實現的。
3.0 參數綁定與重用 Prepared Statements
在之前的討論中,都假設每個 SQL 語句都只準備一次( prepared once),執行(evaluated),然后銷毀。但是,SQLite 允許相同的 prepared statement 被執行多次。通過以下的方法實現:
sqlite3_reset() sqlite3_bind()
sqlite3_step() 執行一次或多次 prepared statement 后,通過 sqlite3_reset() 可以重置并重新執行(evaluated)。對現存的 prepared statement 使用 sqlite3_reset() 可以避免調用 sqlite3_prepare() 創建一個新的 prepared statement。對于部分的 SQL 語句,調用sqlite3_prepare() 的時間和調用 sqlite3_step() 一樣。所以避免調用sqlite3_prepare() 對性能提升有重大的影響。
通常不會對一個 SQL 語句執行(evaluate)多次。更常見的是,執行一個相似的語句。例如,你想通過執行多次 INSERT 語句插入不同的值。為了實現類似的靈活性,SQLite 允許對一條 SQL 語句每次“綁定”不同的值。這些值之后可以改變,并且同樣的 prepared statement 使用新的值可以二次使用。(譯注:說白了就是對一個表一次插入多條數據,每次插入的不同的值在 SQL 語句中用通配符占位)
在 SQLite 中,任何地方都允許插入字符串字面量(string literal),可以使用以下幾種形式:
? ?NNN :AAA $AAA @AAA
在上面個的例子中,NNN 代表整型值( integer value ),AAA 是個標識符(identifier)(譯注:字母數字組合)。參數的初始值為 NULL。在第一次調用 sqlite3_step() 之前或立即在調用 sqlite3_reset() 之后,應用程序可以調用某個 sqlite3_bind() 接口綁定值到參數上。每次調用 sqlite3_bind() 都會覆蓋之前綁定到相同參數的值。
應用可以按需要提前準備多個 SQL prepared statements 并按需要執行(evaluate)。沒有嚴格的限制 prepared statements 的數量。
4.0 配置 SQLite
默認的 SQLite 配置對于大部分的應用工作的都挺好的。但有時開發者想要優化設置項去嘗試壓榨出更多的性能,或者利用一些隱蔽的特性。
sqlite3_config() 可以設置 SQLite 全局的,進程級(process-wide)的配置項。sqlite3_config() 只能在數據庫連接建立后被調用。sqlite3_config() 允許程序員做以下的事情:
調整 SQLite 如何分配內存,包括為安全敏感(safety-critical)的實時的嵌入式系統和應用程序定義的(application-defined)內存分配器設置為可選的(alternative)內存分配器(memory allocators)。 設置一個進程級的錯誤日志。 指定一個應用程序定義的頁緩存(page cache)。 調整 mutex 的使用,這樣就可以使用多種線程模型,或者替換一個程序定義的 mutex 系統。
在進程級的設置完成(configuration is complete)并且數據庫連接已經創建后,不同的數據庫連接可以通過調用 sqlite3_limit() 和 sqlite3_db_config() 配置。
5.0 擴展 SQLite
SQLite 包含可以擴展功能的接口。這些接口(routine)包括:
sqlite3_create_collation() sqlite3_create_function() sqlite3_create_module() sqlite3_vfs_register()
sqlite3_create_collation() 接口用于創建排序文字用的新的校對隊列(collating sequences)。sqlite3_create_module() 接口用于注冊新的虛表實現。sqlite3_vfs_register() 創建一個新的 VFS(譯注:Virtual File System,虛擬文件系統)。
sqlite3_create_function() 接口用于創建新的 SQL 函數(function)—— scalar 函數或者 aggregate 函數(譯注:http://www.w3schools.com/sql/sql_functions.asp)。新的函數實現通常使用以下的額外接口:
sqlite3_aggregate_context() sqlite3_result() sqlite3_user_data() sqlite3_value()
所有的 SQLite 內建 SQL 函數都使用的是這些接口創建的。可以參考 SQLite 的源文件,尤其是 date.c 和 func.c。
共享庫或者 DLL 可以作為 SQLite 的可裝卸擴展(loadable extensions)(譯注:http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions)。
6.0 其他接口
這篇文章只提到了 SQLite 的一些基礎接口。SQLite 庫中還包含一些這里沒有提到的有用的 API。可以在 SQLite 的 C/C++ 的接口說明中找到完整的函數列表(譯注:http://sqlite.org/c3ref/intro.html)。參考此文檔可以找到完整和權威的關于 SQLite 接口的信息。
來源:Cocoabit