Linux平台上SQLite数据库教程(二)——C语言API介绍
http://blog.csdn.net/u011192270/article/details/48086961
前言:本文將介紹幾個基本的SQLite3數據庫的C語言API接口,主要用到兩個文件:sqlite3.c、sqlite3.h。源碼地址:https://github.com/AnSwErYWJ/SQLite。
打開數據庫
1.原型:
int sqlite3_open(const char* filename, /* 數據庫文件名, 必須為 UTF-8 格式 */sqlite3** ppDB /* 輸出: SQLite 數據庫句柄 */ );;- 1
- 2
- 3
- 4
2.說明:?
參數filename為指定打開的數據庫, sqlite3的結構指針?*ppDB?為數據庫連接句柄。如果數據庫被成功打開(和/或 創建), 函數返回?SQLITE_OK;否則返回一個錯誤碼, 可以通過* sqlite3_errmsg()* 查看錯誤原因.。出錯,則只可能是?SQLite?無法為?SQLite?對象分配內存空間, 此時將返回 NULL。
關閉數據庫
1.原型:
int sqlite3_close(sqlite3* pDB /* 由 sqlite3_open 或基相關的函數打開的 SQLite 對象句柄 */);- 1
- 2
- 3
2.說明:?
該函數用來關閉 sqlite3 對象。返回?SQLITE_OK?表示對象被成功關閉,以及所有相關的資源被成功回收。應用程序必須在關閉之前 “完成(finalize)” 所有的 “預編譯語句(prepared statements)”, 并且關閉所有的 “二進制句柄綁定(BLOB handle)”, 如果在關閉時還有未完成的預編譯語句或二進制句柄, 那么函數返回 SQLITE_BUSY(5)。
錯誤處理
原型1:
const char *sqlite3_errmsg(sqlite3* pDB /* SQLite3 數據庫句柄 */ );- 1
- 2
- 3
說明1:?
該函數返回與pDB數據庫指針相關的錯誤信息,下次調用會覆蓋。
原型2:
int sqlite3_errcode(sqlite3* pDB /* SQLite3 數據庫句柄 */ )- 1
- 2
- 3
說明2:?
該函數返回最近一次調用 sqlite3_ API時產生的錯誤碼。
示例一:
/************************************************************************* > File Name: example1.c > Author: AnSwEr > Mail: 1045837697@qq.com > Created Time: 2015年08月29日 星期六 14時17分21秒************************************************************************/#include<stdio.h> #include<stdlib.h> #include"sqlite3.h"int main(void) { char *filename = "./first.db"; sqlite3 *pDB = NULL; int ret = 0; ret = sqlite3_open(filename,&pDB); if(ret != SQLITE_OK) { fprintf(stderr,"%s\n",sqlite3_errmsg(pDB)); exit(EXIT_FAILURE); } /*do something*/ printf("open successfully!\n"); if(pDB != NULL) { sqlite3_close(pDB); pDB = NULL; } printf("close successfully!\n"); return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
示例一實現打開和關閉操作。
執行sql語句
原型:
int sqlite3_exec(sqlite3* pDB, /* sqlite3句柄 */const char* sql, /* 被執行的 SQL 語句 */int (*callback)(void*,int,char**,char**), /* 執行/查詢回調函數 */void* pvoid, /* 傳遞給回調函數的第一個參數 */char**errmsg /* 錯誤輸出信息 */ );- 1
- 2
- 3
- 4
- 5
- 6
- 7
說明:?
當回調函數不為?NULL, 則它對每一個行查詢結果都會調用該回調函數;如果沒有回調函數被指定,?sqlite3_exec()?只是簡單地忽略查詢結果。?
如果回調函數返回非零,sqlite3_exec()?立即中斷查詢,并且不再執行后續的?SQL?語句,也不再調用回調函數,?sqlite3_exec()?將返回?SQLITE_ABORT?結束執行。?
當發生錯誤時, 執行將中斷。如果?errmsg?參數不為空,錯誤信息將會被寫入(errmsg?由?sqlite3_malloc()?分配內存空間,由sqlite3_free()?釋放該內存空間)。如果?errmsg?參數不為?NULL, 并且沒有錯誤發生, errmsg 被設置為?NULL。?
通常情況下callback在select操作中會使用到,如果不需要回調函數。第三第四個參數設為NULL。
回調函數原型:
int callback(void *params, /*params是sqlite3_exec傳入的第四個參數*/int column_size, /*column_size是結果字段的個數*/char **column_value, /*column_value是返回記錄的一位字符數組指針*/char **column_name /*column_name是結果字段的名稱*/ );- 1
- 2
- 3
- 4
- 5
- 6
示例二
/*************************************************************************> File Name: example2.c> Author: AnSwEr> Mail: 1045837697@qq.com> Created Time: 2015年08月29日 星期六 20時11分06秒************************************************************************//** 查詢數據庫*/ #include<stdio.h> #include<stdlib.h> #include"sqlite3.h"static print_info(void *params,int column_size,char **column_value,char **column_name) {int i;for(i=0;i<column_size;i++)printf("\t%s",column_value[i]);printf("\n");return 0; }int main(void) {char *filename = "./first.db";sqlite3 *pDB = NULL;int ret = 0;/*open*/ret = sqlite3_open(filename,&pDB);if(ret != SQLITE_OK){fprintf(stderr,"%s\n",sqlite3_errmsg(pDB));exit(EXIT_FAILURE);}/*select*/char *errmsg = 0;ret = sqlite3_exec(pDB,"select * from stutable",print_info,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"select error:%s\n",errmsg);sqlite3_free(errmsg);/*close*/if(pDB != NULL){sqlite3_close(pDB);pDB = NULL;}return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
示例二執行使用回調函數的select語句。此外,還有不使用回調函數的select語句(使用sqlite3_get_table,此函數是sqlite3_exec的包裝)。 不過個人感覺還是使用回調函數好,這樣代碼可看性強,更整潔。
sqlite3_get_table原型:
int sqlite3_get_table(sqlite3 *db, /* An open database */const char *zSql, /* SQL to be evaluated */char ***pazResult, /* Results of the query */int *pnRow, /* Number of result rows written here */int *pnColumn, /* Number of result columns written here */char **pzErrmsg /* Error msg written here */ ); void sqlite3_free_table(char **result);/* db是sqlite3的句柄 zSql是要執行的sql語句 pazResult是執行查詢操作的返回結果集 pnRow是記錄的行數 pnColumn是記錄的字段個數 pzErrmsg是錯誤信息pazResult是一個(pnRow+1)*pnColumn結果集的字符串數組,其中前pnColumn個結果是字段的名稱,后pnRow行記錄是真實的字段值,如果某個字段為空,則對應值為NULL。- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
這里貼一段網上查到的不使用回調函數的select示例:
char **dbresult; int j,nrow,ncolumn,index; //select tableret = sqlite3_get_table(db,"select * from t",&dbresult,&nrow,&ncolumn,&errmsg);if(ret == SQLITE_OK){printf("query %i records.\n",nrow);index=ncolumn;for(i=0;i<nrow;i++){printf("[%2i]",i);for(j=0;j<ncolumn;j++){printf(" %s",dbresult[index]);index++;}printf("\n");}}sqlite3_free_table(dbresult);- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
示例三
/*************************************************************************> File Name: example3.c> Author: AnSwEr> Mail: 1045837697@qq.com> Created Time: 2015年08月29日 星期六 20時44分10秒************************************************************************//** 表的創建與刪除,數據的插入,更新與刪除。*/#include<stdio.h> #include<stdlib.h> #include"sqlite3.h"static print_info(void *params,int column_size,char **column_value,char **column_name) {int i;for(i=0;i<column_size;i++)printf("\t%s",column_value[i]);printf("\n");return 0; }int main(void) {char *filename = "./first.db";sqlite3 *pDB = NULL;int ret = 0;/*open*/ret = sqlite3_open(filename,&pDB);if(ret != SQLITE_OK){fprintf(stderr,"%s\n",sqlite3_errmsg(pDB));exit(EXIT_FAILURE);}/*創建表*/const char *create_table = "create table t(id int primary key,name vachar(128))";char *errmsg = 0;ret = sqlite3_exec(pDB,create_table,NULL,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"create table error:%s\n",errmsg);sqlite3_free(errmsg);/*插入數據*/const char *insert_data = "insert into t(id,name) values(1,'answer')";ret = sqlite3_exec(pDB,insert_data,NULL,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"insert data error:%s\n",errmsg);/*查詢表中數據*/ret = sqlite3_exec(pDB,"select * from t",print_info,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"select error:%s\n",errmsg);printf("\n");/*更新表中數據*/const char *update_data = "update t set name='jack' where id=1";ret = sqlite3_exec(pDB,update_data,NULL,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"update_data error:%s\n",errmsg);/*查詢表中數據*/ret = sqlite3_exec(pDB,"select * from t",print_info,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"select error:%s\n",errmsg);printf("\n");/*刪除數據*/const char *delete_data = "delete from t where id = 1";ret = sqlite3_exec(pDB,delete_data,NULL,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"delete data error:%s\n",errmsg);/*查詢受上次操作影響的記錄數*/printf("delete data records:%i\n",sqlite3_changes(pDB));printf("\n");/*刪除表*/const char *drop_table = "drop table if exists t";ret = sqlite3_exec(pDB,drop_table,NULL,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"drop table error:%s\n",errmsg);/*close*/if(pDB != NULL){sqlite3_close(pDB);pDB = NULL;}return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
示例三演示創建\刪除表,數據的插入、更新與刪除。
預編譯操作
注意:sqlite3_exec中已經封裝了預編譯操作,直接使用即可,預編譯操作只需稍作了解。
網上查了很多sqlite的預編譯操作的例子,比較復雜,大致可以分為以下幾個步驟:?
1. 通過sqlite3_prepare創建一個sqlite3_stmt對象?
2. 通過sqlite3_bind_*()綁定預編譯字段的值?
3. 通過sqlite3_step()執行SQL語句?
4. 通過sqlite3_reset()重置預編譯語句,重復操作2多次?
5. 通過sqlite3_finalize()銷毀資源
下面依次來看看這些函數。
sqlite3_prepare原型:
int sqlite3_prepare(sqlite3* pDB, /* 成功打開的數據庫句柄 */const char* sql, /* UTF8編碼的 SQL 語句 */int nbytes, /* 參數 sql 的字節數, 包含 '\0' */sqlite3_stmt** ppStmt, /* 輸出:預編譯語句句柄 */const char** pszTail /* 輸出:指向 sql 語句中未使用的部分 */ );- 1
- 2
- 3
- 4
- 5
- 6
- 7
說明:?
如果nbytes小于0,?sql?語句則以第一個 ‘\0’終結。如果它非負,,則為讀取的最大長度.。當nbytes?大于 0 時,則讀取指定長度,如果’\0’先被讀到,則以’\0’結束。如果用戶知道被傳入的 sql 語句是以 ‘\0’ 結尾的,那么有一個更好的做法是:把nbytes的值設為該字符串的長度(包含’\0’),這樣可以避免 SQLite 復制該字符串的一份拷貝, 以提高程序的效率。?
如果?pszTail?不為 NULL, 則?*pszTail?指向?sql?中第一個被傳入的 SQL 語句的結尾。該函數只編譯?sql?的第一個語句, 所以 *pszTail 指向的內容則是未被編譯的。?
*ppStmt?指向一條可以被?sqlie3_step()?函數使用的預編譯語句.。如果有錯誤發生,?pszStmt 的值為*NULL。?
調用者應該使用?sqlite3_finalize()?刪掉被預編譯的語句。?
如果函數成功, 返回?SQLITE_OK, 否則返回一個錯誤碼。
sqlite3_bind_*有多種形式,分別對應不同的數據類型:
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); int sqlite3_bind_double(sqlite3_stmt*, int, double); int sqlite3_bind_int(sqlite3_stmt*, int, int); int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); int sqlite3_bind_null(sqlite3_stmt*, int); int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
預編譯SQL語句中可以包含如下幾種形式:
? ?NNN :VVV @VVV $VVV- 1
- 2
- 3
- 4
- 5
NNN代表數字,VVV代表字符串.?
如果是?或者?NNN,那么可以直接sqlite3_bind_*()進行操作,如果是字符串,還需要通過sqlite3_bind_parameter_index()獲取對應的index,然后再調用sqlite3_bind_*()操作。這通常用于構造不定條件的SQL語句(動態SQL語句)。
int sqlite3_step原型:
int sqlite3_step(sqlite3_stmt* ppStmt /* 一條被預編譯的 sql 語句 */ );- 1
- 2
- 3
說明:?
當一條語句被 sqlite3_prepare() 或其相關的函數預編譯后, sqlite3_step() 必須被調用一次或多次來評估該預編譯語句。?
該函數的詳細行為依賴于由 sqlite3_prepare()(或其相關的函數) 產生的是一條怎樣的預編譯語句。
返回值:?
SQLITE_BUSY:忙碌. 數據庫引擎無法鎖定數據去完成其工作。但可以多次嘗試。?
SQLITE_DONE:完成. sql 語句已經被成功地執行。在調用 sqlite_reset() 之前, 當前預編譯的語句不應該被 sqlite3_step() 再次調用。?
SQLITE_ROW:查詢時產生了結果。此時可以通過相關的”數據訪問函數(column access functions)”來取得數據. sqlite3_step() 的再一次調用將取得下一條查詢結果。?
SQLITE_ERROR:發生了錯誤。 此時可以通過 sqlite3_errmmsg() 取得相關的錯誤信息. sqlite3_step() 不能被再次調用。?
SQLITE_MISUSE:不正確的庫的使用. 該函數使用不當。
sqlite3_finalize原型:
int sqlite3_finalize(sqlite3_stmt* pStmt /* 被預編譯的語句 */ );- 1
- 2
- 3
說明:?
該函數用來刪除一條被預編譯的 sql 語句。
預編譯實現代碼:
int i = 0;sqlite3_stmt *stmt;char ca[255];//預編譯操作sqlite3_prepare_v2(db,"insert into t(id,msg) values(?,?)",-1,&stmt,0);for(i=10;i<20;i++){sprintf(ca,"HELLO#%i",i);sqlite3_bind_int(stmt,1,i);sqlite3_bind_text(stmt,2,ca,strlen(ca),NULL);sqlite3_step(stmt);sqlite3_reset(stmt);}sqlite3_finalize(stmt);stmt = NULL;- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
總結
上文列出的是一些最基本精簡的C語言API,sqlite為C語言一共提供了200多個API。不過,上述這些API對一般的開發者而言已經足夠了,如果你還有更多的需求,那就請查閱前言中給出的源代碼文件(sqlite3.c,sqlite3.h)。
反饋與建議
- 微博:@AnSwEr不是答案
- github:AnSwErYWJ
- 博客:AnSwEr不是答案的專欄
總結
以上是生活随笔為你收集整理的Linux平台上SQLite数据库教程(二)——C语言API介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 丐侠传奇剧情介绍
- 下一篇: Linux多线程——使用信号量同步线程