Linux平台上SQLite数据库教程(二)——C语言API介绍
http://blog.csdn.net/u011192270/article/details/48086961
前言:本文將介紹幾個(gè)基本的SQLite3數(shù)據(jù)庫的C語言API接口,主要用到兩個(gè)文件:sqlite3.c、sqlite3.h。源碼地址:https://github.com/AnSwErYWJ/SQLite。
打開數(shù)據(jù)庫
1.原型:
int sqlite3_open(const char* filename, /* 數(shù)據(jù)庫文件名, 必須為 UTF-8 格式 */sqlite3** ppDB /* 輸出: SQLite 數(shù)據(jù)庫句柄 */ );;- 1
- 2
- 3
- 4
2.說明:?
參數(shù)filename為指定打開的數(shù)據(jù)庫, sqlite3的結(jié)構(gòu)指針?*ppDB?為數(shù)據(jù)庫連接句柄。如果數(shù)據(jù)庫被成功打開(和/或 創(chuàng)建), 函數(shù)返回?SQLITE_OK;否則返回一個(gè)錯(cuò)誤碼, 可以通過* sqlite3_errmsg()* 查看錯(cuò)誤原因.。出錯(cuò),則只可能是?SQLite?無法為?SQLite?對(duì)象分配內(nèi)存空間, 此時(shí)將返回 NULL。
關(guān)閉數(shù)據(jù)庫
1.原型:
int sqlite3_close(sqlite3* pDB /* 由 sqlite3_open 或基相關(guān)的函數(shù)打開的 SQLite 對(duì)象句柄 */);- 1
- 2
- 3
2.說明:?
該函數(shù)用來關(guān)閉 sqlite3 對(duì)象。返回?SQLITE_OK?表示對(duì)象被成功關(guān)閉,以及所有相關(guān)的資源被成功回收。應(yīng)用程序必須在關(guān)閉之前 “完成(finalize)” 所有的 “預(yù)編譯語句(prepared statements)”, 并且關(guān)閉所有的 “二進(jìn)制句柄綁定(BLOB handle)”, 如果在關(guān)閉時(shí)還有未完成的預(yù)編譯語句或二進(jìn)制句柄, 那么函數(shù)返回 SQLITE_BUSY(5)。
錯(cuò)誤處理
原型1:
const char *sqlite3_errmsg(sqlite3* pDB /* SQLite3 數(shù)據(jù)庫句柄 */ );- 1
- 2
- 3
說明1:?
該函數(shù)返回與pDB數(shù)據(jù)庫指針相關(guān)的錯(cuò)誤信息,下次調(diào)用會(huì)覆蓋。
原型2:
int sqlite3_errcode(sqlite3* pDB /* SQLite3 數(shù)據(jù)庫句柄 */ )- 1
- 2
- 3
說明2:?
該函數(shù)返回最近一次調(diào)用 sqlite3_ API時(shí)產(chǎn)生的錯(cuò)誤碼。
示例一:
/************************************************************************* > File Name: example1.c > Author: AnSwEr > Mail: 1045837697@qq.com > Created Time: 2015年08月29日 星期六 14時(shí)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
示例一實(shí)現(xiàn)打開和關(guān)閉操作。
執(zhí)行sql語句
原型:
int sqlite3_exec(sqlite3* pDB, /* sqlite3句柄 */const char* sql, /* 被執(zhí)行的 SQL 語句 */int (*callback)(void*,int,char**,char**), /* 執(zhí)行/查詢回調(diào)函數(shù) */void* pvoid, /* 傳遞給回調(diào)函數(shù)的第一個(gè)參數(shù) */char**errmsg /* 錯(cuò)誤輸出信息 */ );- 1
- 2
- 3
- 4
- 5
- 6
- 7
說明:?
當(dāng)回調(diào)函數(shù)不為?NULL, 則它對(duì)每一個(gè)行查詢結(jié)果都會(huì)調(diào)用該回調(diào)函數(shù);如果沒有回調(diào)函數(shù)被指定,?sqlite3_exec()?只是簡單地忽略查詢結(jié)果。?
如果回調(diào)函數(shù)返回非零,sqlite3_exec()?立即中斷查詢,并且不再執(zhí)行后續(xù)的?SQL?語句,也不再調(diào)用回調(diào)函數(shù),?sqlite3_exec()?將返回?SQLITE_ABORT?結(jié)束執(zhí)行。?
當(dāng)發(fā)生錯(cuò)誤時(shí), 執(zhí)行將中斷。如果?errmsg?參數(shù)不為空,錯(cuò)誤信息將會(huì)被寫入(errmsg?由?sqlite3_malloc()?分配內(nèi)存空間,由sqlite3_free()?釋放該內(nèi)存空間)。如果?errmsg?參數(shù)不為?NULL, 并且沒有錯(cuò)誤發(fā)生, errmsg 被設(shè)置為?NULL。?
通常情況下callback在select操作中會(huì)使用到,如果不需要回調(diào)函數(shù)。第三第四個(gè)參數(shù)設(shè)為NULL。
回調(diào)函數(shù)原型:
int callback(void *params, /*params是sqlite3_exec傳入的第四個(gè)參數(shù)*/int column_size, /*column_size是結(jié)果字段的個(gè)數(shù)*/char **column_value, /*column_value是返回記錄的一位字符數(shù)組指針*/char **column_name /*column_name是結(jié)果字段的名稱*/ );- 1
- 2
- 3
- 4
- 5
- 6
示例二
/*************************************************************************> File Name: example2.c> Author: AnSwEr> Mail: 1045837697@qq.com> Created Time: 2015年08月29日 星期六 20時(shí)11分06秒************************************************************************//** 查詢數(shù)據(jù)庫*/ #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
示例二執(zhí)行使用回調(diào)函數(shù)的select語句。此外,還有不使用回調(diào)函數(shù)的select語句(使用sqlite3_get_table,此函數(shù)是sqlite3_exec的包裝)。 不過個(gè)人感覺還是使用回調(diào)函數(shù)好,這樣代碼可看性強(qiáng),更整潔。
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是要執(zhí)行的sql語句 pazResult是執(zhí)行查詢操作的返回結(jié)果集 pnRow是記錄的行數(shù) pnColumn是記錄的字段個(gè)數(shù) pzErrmsg是錯(cuò)誤信息pazResult是一個(gè)(pnRow+1)*pnColumn結(jié)果集的字符串?dāng)?shù)組,其中前pnColumn個(gè)結(jié)果是字段的名稱,后pnRow行記錄是真實(shí)的字段值,如果某個(gè)字段為空,則對(duì)應(yīng)值為NULL。- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
這里貼一段網(wǎng)上查到的不使用回調(diào)函數(shù)的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時(shí)44分10秒************************************************************************//** 表的創(chuàng)建與刪除,數(shù)據(jù)的插入,更新與刪除。*/#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);}/*創(chuàng)建表*/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);/*插入數(shù)據(jù)*/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);/*查詢表中數(shù)據(jù)*/ret = sqlite3_exec(pDB,"select * from t",print_info,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"select error:%s\n",errmsg);printf("\n");/*更新表中數(shù)據(jù)*/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);/*查詢表中數(shù)據(jù)*/ret = sqlite3_exec(pDB,"select * from t",print_info,NULL,&errmsg);if(ret != SQLITE_OK)fprintf(stderr,"select error:%s\n",errmsg);printf("\n");/*刪除數(shù)據(jù)*/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);/*查詢受上次操作影響的記錄數(shù)*/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
示例三演示創(chuàng)建\刪除表,數(shù)據(jù)的插入、更新與刪除。
預(yù)編譯操作
注意:sqlite3_exec中已經(jīng)封裝了預(yù)編譯操作,直接使用即可,預(yù)編譯操作只需稍作了解。
網(wǎng)上查了很多sqlite的預(yù)編譯操作的例子,比較復(fù)雜,大致可以分為以下幾個(gè)步驟:?
1. 通過sqlite3_prepare創(chuàng)建一個(gè)sqlite3_stmt對(duì)象?
2. 通過sqlite3_bind_*()綁定預(yù)編譯字段的值?
3. 通過sqlite3_step()執(zhí)行SQL語句?
4. 通過sqlite3_reset()重置預(yù)編譯語句,重復(fù)操作2多次?
5. 通過sqlite3_finalize()銷毀資源
下面依次來看看這些函數(shù)。
sqlite3_prepare原型:
int sqlite3_prepare(sqlite3* pDB, /* 成功打開的數(shù)據(jù)庫句柄 */const char* sql, /* UTF8編碼的 SQL 語句 */int nbytes, /* 參數(shù) sql 的字節(jié)數(shù), 包含 '\0' */sqlite3_stmt** ppStmt, /* 輸出:預(yù)編譯語句句柄 */const char** pszTail /* 輸出:指向 sql 語句中未使用的部分 */ );- 1
- 2
- 3
- 4
- 5
- 6
- 7
說明:?
如果nbytes小于0,?sql?語句則以第一個(gè) ‘\0’終結(jié)。如果它非負(fù),,則為讀取的最大長度.。當(dāng)nbytes?大于 0 時(shí),則讀取指定長度,如果’\0’先被讀到,則以’\0’結(jié)束。如果用戶知道被傳入的 sql 語句是以 ‘\0’ 結(jié)尾的,那么有一個(gè)更好的做法是:把nbytes的值設(shè)為該字符串的長度(包含’\0’),這樣可以避免 SQLite 復(fù)制該字符串的一份拷貝, 以提高程序的效率。?
如果?pszTail?不為 NULL, 則?*pszTail?指向?sql?中第一個(gè)被傳入的 SQL 語句的結(jié)尾。該函數(shù)只編譯?sql?的第一個(gè)語句, 所以 *pszTail 指向的內(nèi)容則是未被編譯的。?
*ppStmt?指向一條可以被?sqlie3_step()?函數(shù)使用的預(yù)編譯語句.。如果有錯(cuò)誤發(fā)生,?pszStmt 的值為*NULL。?
調(diào)用者應(yīng)該使用?sqlite3_finalize()?刪掉被預(yù)編譯的語句。?
如果函數(shù)成功, 返回?SQLITE_OK, 否則返回一個(gè)錯(cuò)誤碼。
sqlite3_bind_*有多種形式,分別對(duì)應(yīng)不同的數(shù)據(jù)類型:
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
預(yù)編譯SQL語句中可以包含如下幾種形式:
? ?NNN :VVV @VVV $VVV- 1
- 2
- 3
- 4
- 5
NNN代表數(shù)字,VVV代表字符串.?
如果是?或者?NNN,那么可以直接sqlite3_bind_*()進(jìn)行操作,如果是字符串,還需要通過sqlite3_bind_parameter_index()獲取對(duì)應(yīng)的index,然后再調(diào)用sqlite3_bind_*()操作。這通常用于構(gòu)造不定條件的SQL語句(動(dòng)態(tài)SQL語句)。
int sqlite3_step原型:
int sqlite3_step(sqlite3_stmt* ppStmt /* 一條被預(yù)編譯的 sql 語句 */ );- 1
- 2
- 3
說明:?
當(dāng)一條語句被 sqlite3_prepare() 或其相關(guān)的函數(shù)預(yù)編譯后, sqlite3_step() 必須被調(diào)用一次或多次來評(píng)估該預(yù)編譯語句。?
該函數(shù)的詳細(xì)行為依賴于由 sqlite3_prepare()(或其相關(guān)的函數(shù)) 產(chǎn)生的是一條怎樣的預(yù)編譯語句。
返回值:?
SQLITE_BUSY:忙碌. 數(shù)據(jù)庫引擎無法鎖定數(shù)據(jù)去完成其工作。但可以多次嘗試。?
SQLITE_DONE:完成. sql 語句已經(jīng)被成功地執(zhí)行。在調(diào)用 sqlite_reset() 之前, 當(dāng)前預(yù)編譯的語句不應(yīng)該被 sqlite3_step() 再次調(diào)用。?
SQLITE_ROW:查詢時(shí)產(chǎn)生了結(jié)果。此時(shí)可以通過相關(guān)的”數(shù)據(jù)訪問函數(shù)(column access functions)”來取得數(shù)據(jù). sqlite3_step() 的再一次調(diào)用將取得下一條查詢結(jié)果。?
SQLITE_ERROR:發(fā)生了錯(cuò)誤。 此時(shí)可以通過 sqlite3_errmmsg() 取得相關(guān)的錯(cuò)誤信息. sqlite3_step() 不能被再次調(diào)用。?
SQLITE_MISUSE:不正確的庫的使用. 該函數(shù)使用不當(dāng)。
sqlite3_finalize原型:
int sqlite3_finalize(sqlite3_stmt* pStmt /* 被預(yù)編譯的語句 */ );- 1
- 2
- 3
說明:?
該函數(shù)用來刪除一條被預(yù)編譯的 sql 語句。
預(yù)編譯實(shí)現(xiàn)代碼:
int i = 0;sqlite3_stmt *stmt;char ca[255];//預(yù)編譯操作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
總結(jié)
上文列出的是一些最基本精簡的C語言API,sqlite為C語言一共提供了200多個(gè)API。不過,上述這些API對(duì)一般的開發(fā)者而言已經(jīng)足夠了,如果你還有更多的需求,那就請(qǐng)查閱前言中給出的源代碼文件(sqlite3.c,sqlite3.h)。
反饋與建議
- 微博:@AnSwEr不是答案
- github:AnSwErYWJ
- 博客:AnSwEr不是答案的專欄
總結(jié)
以上是生活随笔為你收集整理的Linux平台上SQLite数据库教程(二)——C语言API介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 丐侠传奇剧情介绍
- 下一篇: Linux多线程——使用信号量同步线程