SQLite教程(二):C/C++介面簡介,sqlite教程
一、概述:
在SQLite提供的C/C++介面中,其中5個APIs屬於核心介面。在這篇部落格中我們將主要介紹它們的用法,以及它們所涉及到的核心SQLite對象,如database_connection和prepared_statement。相比於其它資料庫引擎提供的APIs,如OCI、MySQL API等,SQLite提供的介面還是非常易於理解和掌握的。
二、核心對象和介面:
1. 核心對象:
在SQLite中最主要的兩個對象是,database_connection和prepared_statement。database_connection對象是由sqlite3_open()介面函數建立並返回的,在應用程式使用任何其他SQLite介面函數之前,必須先調用該函數以便獲得database_connnection對象,在隨後的其他APIs調用中,都需要該對象作為輸入參數以完成相應的工作。至於prepare_statement,我們可以簡單的將它視為編譯後的SQL語句,因此,所有和SQL語句執行相關的函數也都需要該對象作為輸入參數以完成指定的SQL操作。
2. 核心介面:
1). sqlite3_open
上面已經提到過這個函數了,它是操作SQLite資料庫的入口函數。該函數返回的database_connection對象是很多其他SQLite APIs的控制代碼參數。注意,我們通過該函數既可以開啟已經存在的資料庫檔案,也可以建立新的資料庫檔案。對於該函數返回的database_connection對象,我們可以在多個線程之間共用該對象的指標,以便完成和資料庫相關的任意操作。然而在多線程情況下,我們更為推薦的使用方式是,為每個線程建立獨立的database_connection對象。對於該函數還有一點也需要額外說明,我們沒有必要為了訪問多個資料庫而建立多個資料庫連接對象,因為通過SQLite內建的ATTACH命令可以在一個串連中方便的訪問多個資料庫。
2). sqlite3_prepare
該函數將SQL文本轉換為prepared_statement對象,並在函數執行後返回該對象的指標。事實上,該函數並不會評估參數指定SQL語句,它僅僅是將SQL文本初始化為待執行的狀態。最後需要指出的,對於新的應用程式我們可以使用sqlite3_prepare_v2介面函數來替代該函數以完成相同的工作。
3). sqlite3_step
該函數用於評估sqlite3_prepare函數返回的prepared_statement對象,在執行完該函數之後,prepared_statement對象的內部指標將指向其返回的結果集的第一行。如果打算進一步迭代其後的資料行,就需要不斷的調用該函數,直到所有的資料行都遍曆完畢。然而對於INSERT、UPDATE和DELETE等DML語句,該函數執行一次即可完成。
4). sqlite3_column
該函數用於擷取當前行指定列的資料,然而嚴格意義上講,此函數在SQLite的介面函數中並不存在,而是由一組相關的介面函數來完成該功能,其中每個函數都返回不同類型的資料,如:
複製代碼 代碼如下:
sqlite3_column_blob
sqlite3_column_bytes
sqlite3_column_bytes16
sqlite3_column_double
sqlite3_column_int
sqlite3_column_int64
sqlite3_column_text
sqlite3_column_text16
sqlite3_column_type
sqlite3_column_value
sqlite3_column_count
其中sqlite3_column_count函數用於擷取當前結果集中的欄位資料。下面是使用sqlite3_step和sqlite3_column函數迭代結果集中每行資料的虛擬碼,注意這裡作為範例程式碼簡化了對欄位類型的判斷:
複製代碼 代碼如下:
int fieldCount = sqlite3_column_count(...);
while (sqlite3_step(...) <> EOF) {
for (int i = 0; i < fieldCount; ++i) {
int v = sqlite3_column_int(...,i);
}
}
5). sqlite3_finalize
該函數用於銷毀prepared statement對象,否則將會造成記憶體泄露。
6). sqlite3_close
該函數用於關閉之前開啟的database_connection對象,其中所有和該對象相關的prepared_statements對象都必須在此之前先被銷毀。
三、參數綁定:
和大多數關係型資料庫一樣,SQLite的SQL文本也支援變數綁定,以便減少SQL語句被動態解析的次數,從而提高資料查詢和資料操作的效率。要完成該操作,我們需要使用SQLite提供的另外兩個介面APIs,sqlite3_reset和sqlite3_bind。見如下樣本:
複製代碼 代碼如下:
void test_parameter_binding() {
//1. 不帶參數綁定的情況下插入多條資料。
char strSQL[128];
for (int i = 0; i < MAX_ROWS; ++i) {
sprintf(strSQL,"insert into testtable values(%d)",i);
sqlite3_prepare_v2(..., strSQL);
sqlite3_step(prepared_stmt);
sqlite3_finalize(prepared_stmt);
}
//2. 參數綁定的情況下插入多條資料。
string strSQLWithParameter = "insert into testtable values(?)";
sqlite3_prepare_v2(..., strSQL);
for (int i = 0; i < MAX_ROWS; ++i) {
sqlite3_bind(...,i);
sqlite3_step(prepared_stmt);
sqlite3_reset(prepared_stmt);
}
sqlite3_finalize(prepared_stmt);
}
這裡首先需要說明的是,SQL語句"insert into testtable values(?)"中的問號(?)表示參數變數的預留位置,該規則在很多關係型資料庫中都是一致的,因此這對於資料庫移植操作還是比較方便的。
通過上面的範例程式碼可以顯而易見的看出,參數綁定寫法的執行效率要高於每次產生不同的SQL語句的寫法,即2)在效率上要明顯優於1),下面是針對這兩種寫法的具體比較:
1). 單單從程式表面來看,前者在for迴圈中執行了更多的任務,比如字串的填充、SQL語句的prepare,以及prepared_statement對象的釋放。
2). 在SQLite的官方文檔中明確的指出,sqlite3_prepare_v2的執行效率往往要低於sqlite3_step的效率。
3). 當插入的資料量較大時,後者帶來的效率提升還是相當可觀的。