文章目錄
關於數據庫
1、客戶端、服務器和數據庫
- 服務器:保存、處理、分發數據。
- 客戶端:收集、展示數據。
- 數據庫:規範地管理和存儲數據。
- 三者之間的關係:
2、目前國內比較流行的數據庫管理系統
-
Mysql
Mysql是開源的、快速的、可靠的、易於使用的關係型數據庫管理系統,Mysql可以工作在嵌入式系統中,功能比較強大,內存佔用比較大。 -
sql server
微軟開發的用於web服務器上最流行的數據庫管理系統,以其簡便的操作和友好的界面深受廣大用戶的喜愛。 -
oracle
甲骨文公司研發的開放的數據庫管理系統,操作較爲複雜,功能比較強大,在世界上應用最廣泛的數據庫。 -
總結
在當今大數據形勢的推動下,數據的管理極爲重要,事物的誕生往往是因爲需求,數據庫就是用來管理和保護數據的。數據庫技術的發展越來越完善,各個數據庫之間沒有誰強誰弱之說,只能說各個數據庫的使用場合不一樣,比如在嵌入式領域,數據庫往往是用來暫時存儲小量數據的,基本輕量級的數據庫就可以滿足需求,大型複雜的數據庫管理系統反而會影響嵌入式系統的運行效率。
sqlite介紹
-
sqlite的背景
sqlite是全開源的,可以免費用作任何目的。SQLite代碼庫由一支全職從事SQLite工作的國際開發人員團隊支持 。開發人員繼續擴展SQLite的功能並增強其可靠性和性能,同時保持與已發佈的接口規範, SQL語法和數據庫文件格式的向後兼容性 。源代碼對於任何想要它的人都是絕對免費的,但是也可以提供專業支持。 -
爲什麼適用於嵌入式
sqlite是c語言編寫的嵌入式數據庫管理系統,代碼量少於3萬行,庫小於600KB,稱其爲輕量級數據庫,它僅僅是一個“庫”,並不是數據庫服務器,因此不需要單獨的服務器進程,sqlite直接讀取和寫入磁盤文件,根據系統提供的內存大小,運行速度不一樣,一般情況下,內存越大,運行速度越快,可能比直接文件系統IO–fwrite、fread快(參考鏈接)。 -
特點
(1)無服務器:大多少數據庫基於客戶端/服務器的,通過網絡訪問數據庫服務器。sqlite直接存取磁盤,沒有中間服務器層,主要優點是無需安裝,設置,配置,初始化,管理和排除故障的單獨服務器進程,正所謂"零配置"數據庫引擎。(2)單個數據庫文件:sqlite數據庫是單個普通磁盤文件,可以位於目錄層次結構中的任何位置。其他數據庫引擎傾向於將數據存儲爲大量文件,並只能存放在數據庫本身標準的位置,這樣做是爲了保證數據的安全性,同時也給訪問帶來了困難。
(3)穩定的可跨平臺數據庫文件:可以在不同平臺間複製並使用相同的數據庫文件。
(4)清單輸入:sqlite允許用戶將任意類型的值存放在任意列中,這種數據類型叫清單類型,sqlite所特有。
(5)可變長度記錄:sqlite僅使用一行記錄所佔用的磁盤空間,比如將單個字符存放在VARCHAR(100)列中,磁盤空間僅僅被消耗一個字符的空間,而不是100個字符的空間。這是sqlite數據庫比較小的原因之一,數據庫越小,運行越快。
sqlite的shell命令
-
ubuntu上安裝sqlite3:只需要一條命令即可:sudo apt-get install sqlite3; 中間可能會出現缺少依賴包這種情況,我們只需下載相應的依賴包就好了。
-
啓動sqlite3控制檯:sqlite3
-
創建一個test的表:create table test (varchar,int);
-
查看數據庫中所有的表:.table;
-
向表中插入兩條數據:insert into test values();
-
查看錶中所有數據:select * from test;
-
刪除表:drop table test;
-
更多的SQL語句:點擊學習
sqlite C API接口
Linux下使用編程操作sqlite數據庫時,會在c文件中包含<sqlite3.h>頭文件,如果編譯出現下圖所示錯誤,說明沒有相應的函數庫。
解決辦法:
sudo apt-get install libsqlite3-dev
1、連接數據庫
連接sqlite3數據庫,如果數據庫不存在,則創建並打開數據庫,如果此數據庫存在,則打開數據庫。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sqlite3.h>
#define database_name "test.db"//數據庫的名字
int main(int argc, char **argv)
{
sqlite3 *db;//定義數據庫操作句柄
int rv = -1;//函數返回值
rv = sqlite3_open(database_name,&db);//打開數據庫
printf("rv=%d\n",rv);//打印返回值
if(rv < 0)
{
printf("Can't create or open database!:%s\n",sqlite3_errmsg(db));
exit(0);
}
else
{
printf("Creating or opening database successfully!\n");
}
rv = sqlite3_close(db);//關閉數據庫
printf("rv=%d\n",rv);//打印返回值
if(rv < 0)
{
printf("Closing database failly!:%s\n",sqlite3_errmsg(db));
exit(0);
}
else
{
printf("select table successfully!\n");
}
}
代碼解析:
- sqlite3_open
int sqlite3_open(
const char *filename, /*數據庫的名字*/
sqlite3 **ppDb /*輸出數據庫的操作句柄*/
);
功能:按文件名稱打開一個數據庫,如果文件不存在,則自動創建。
返回:創建或打開成功返回SQLITE_OK(0),錯誤返回錯誤碼。
返回值列表:
#define SQLITE_OK 0 /* Successful result /
/ beginning-of-error-codes /
#define SQLITE_ERROR 1 / SQL error or missing database /
#define SQLITE_INTERNAL 2 / Internal logic error in SQLite /
#define SQLITE_PERM 3 / Access permission denied /
#define SQLITE_ABORT 4 / Callback routine requested an abort /
#define SQLITE_BUSY 5 / The database file is locked /
#define SQLITE_LOCKED 6 / A table in the database is locked /
#define SQLITE_NOMEM 7 / A malloc() failed /
#define SQLITE_READONLY 8 / Attempt to write a readonly database /
#define SQLITE_INTERRUPT 9 / Operation terminated by sqlite3_interrupt()/
#define SQLITE_IOERR 10 / Some kind of disk I/O error occurred /
#define SQLITE_CORRUPT 11 / The database disk image is malformed /
#define SQLITE_NOTFOUND 12 / Unknown opcode in sqlite3_file_control() /
#define SQLITE_FULL 13 / Insertion failed because database is full /
#define SQLITE_CANTOPEN 14 / Unable to open the database file /
#define SQLITE_PROTOCOL 15 / Database lock protocol error /
#define SQLITE_EMPTY 16 / Database is empty /
#define SQLITE_SCHEMA 17 / The database schema changed /
#define SQLITE_TOOBIG 18 / String or BLOB exceeds size limit /
#define SQLITE_CONSTRAINT 19 / Abort due to constraint violation /
#define SQLITE_MISMATCH 20 / Data type mismatch /
#define SQLITE_MISUSE 21 / Library used incorrectly /
#define SQLITE_NOLFS 22 / Uses OS features not supported on host /
#define SQLITE_AUTH 23 / Authorization denied /
#define SQLITE_FORMAT 24 / Auxiliary database format error /
#define SQLITE_RANGE 25 / 2nd parameter to sqlite3_bind out of range /
#define SQLITE_NOTADB 26 / File opened that is not a database file /
#define SQLITE_ROW 100 / sqlite3_step() has another row ready /
#define SQLITE_DONE 101 / sqlite3_step() has finished executing /
/ end-of-error-codes */
- sqlite3_errmsg
int sqlite3_errmsg(sqlite3 *);
功能:打印數據庫錯誤信息。
參數:數據庫操作句柄
返回:創建或打開成功返回SQLITE_OK(0),錯誤返回錯誤碼。
- sqlite3_close
int sqlite3_close(sqlite3 *);
功能:關閉數據庫。
參數:數據庫操作句柄
返回:創建或打開成功返回SQLITE_OK(0),錯誤返回錯誤碼。
- 編譯運行
1、出現以下錯誤,原因是sqlite3不是標準庫,gcc編譯連接不上sqlite3函數庫
解決辦法:加上 -lsqlite3
2、運行,成功打開數據庫
3、查看剛剛創建的數據庫文件
2、創建表
在前面創建test.db數據庫中創建一個表。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sqlite3.h>
/*
功能:回調函數
參數:
para:由exec傳入的參數
col_num:查詢出一條記錄有多少個表頭
col_value:查詢出的記錄緩存區
col_name:表示字段的段命
返回:
成功返回0
失敗返回-1
*/
static int callback(void *para, int col_num, char **col_value, char **col_name)
{
int i;
for(i = 0; i < col_num; i++)
{
printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");
}
printf("\n");
return 0;
}
int main(int argc, char **argv)
{
sqlite3 *db;//定義數據庫操作句柄
int rv;//返回值
char *sql;//SQL語句指針
char *z_err_msg;//獲取錯誤信息
rv = sqlite3_open("test.db",&db);//打開數據庫
if(rv)
{
printf("Can't open database!:%s\n",sqlite3_errmsg(db));
exit(0);
}
printf("Opening database successfully!\n");
//製作SQL語句
sql = "create table roommates("\
"stu_id varchar primary key not NULL,"\
"name text not NULL,"\
"age int not NULL,"\
"address varchar,"\
"telephone varchar);";
rv = sqlite3_exec(db,sql,callback,0,&z_err_msg);//執行sql語句
if(rv)
{
printf("SQL error!:%s\n",z_err_msg);//打印錯誤信息
sqlite3_free(z_err_msg);
}
else
{
printf("select table successfully!\n");
}
sqlite3_close(db);//關閉數據庫
return 0;
}
代碼解析:
- sqlite3_exec
int sqlite3_exec{
sqlite3* : open 打開的數據庫操作句柄
const char* sql, : 執行的sql功能語句
*callback, : sql語句對應的回調函數,在下一個實例代碼中細講
void* data, : 傳遞給回調函數的參數
char **errmsq : 函數內部通過malloc返回錯誤信息
}
功能:執行sql語句
返回:成功返回SQLITE_OK,錯誤返回錯誤代碼
- sqlite3_free
int sqlite3_free(char *errmsq);
功能:當執行exec函數時,如果發生錯誤,內部會malloc分配內存存儲錯誤信息,所以需要釋放這塊內存,以免內存泄漏。
返回:成功返回SQLITE_OK,錯誤返回錯誤代碼。
- 編譯運行
- 查看剛剛建的表字段
3、插入數據
向上面創建的roommates表中插入數據。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sqlite3.h>
/*
功能:查詢記錄回調函數
參數:
para:由exec傳入的參數
col_num:查詢出一條記錄有多少個表頭
col_value:查詢出的記錄緩存區
col_name:表示字段的段命
返回:
成功返回0
失敗返回-1
*/
static int callback(void *para, int col_num, char **col_value, char **col_name)
{
int i;
for(i = 0; i < col_num; i++)
{
printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");
}
printf("\n");
return 0;
}
int main(int argc, char **argv)
{
sqlite3 *db;//定義數據庫操作句柄
int rv;//返回值
char *sql;//SQL語句指針
char *z_err_msg;//獲取錯誤信息
rv = sqlite3_open("test.db",&db);//打開數據庫
if(rv)
{
printf("Can't open database!:%s\n",sqlite3_errmsg(db));
exit(0);
}
printf("Opening database successfully!\n");
//製作SQL語句
sql = "insert into roommates(stu_id,name,age,address,telephone)"\
"values('12057','Mr Yang',21,'si chuan','96325874');"\
"insert into roommates(stu_id,name,age,address,telephone)"\
"values('12060','Mr qing',22,'yun nan','96325789');"\
"insert into roommates(stu_id,name,age,address,telephone)"\
"values('12059','Mr wang',20,'gui zhou','96325456');"\
"insert into roommates(stu_id,name,age,address,telephone)"\
"values('12065','Mr qi',22,'shang xi','96325874');";
rv = sqlite3_exec(db,sql,callback,0,&z_err_msg);//執行sql語句
if(rv)
{
printf("SQL error!:%s\n",z_err_msg);//打印錯誤信息
sqlite3_free(z_err_msg);//用於釋放從內存中獲取的錯誤信息字符串
}
else
{
printf("select table successfully!\n");
}
sqlite3_close(db);//關閉數據庫
return 0;
}
- 編譯運行
- 查看錶中數據
4、查詢數據
通過c語言編程接口查詢出roommates表中得記錄。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sqlite3.h>
/*
功能:查詢記錄回調函數
參數:
para:由exec傳入的參數
col_num:查詢出一條記錄有多少個表頭
col_value:查詢出的記錄緩存區
col_name:表示字段的段命
返回:
成功返回0
失敗返回-1
*/
static int callback(void *para, int col_num, char **col_value, char **col_name)
{
int i;
printf("%s\n",(char*)para);
for(i = 0; i < col_num; i++)
{
printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");
}
printf("\n");
return 0;
}
int main(int argc, char **argv)
{
sqlite3 *db;//定義數據庫操作句柄
int rv;//返回值
char *sql;//SQL語句指針
char *z_err_msg;//獲取錯誤信息
char *data = "callback is called:";
rv = sqlite3_open("test.db",&db);//打開數據庫
if(rv)
{
printf("Can't open database!:%s\n",sqlite3_errmsg(db));
exit(0);
}
printf("Opening database successfully!\n");
//製作SQL語句
sql = "select * from roommates";
rv = sqlite3_exec(db,sql,callback,(void *)data,&z_err_msg);//執行sql語句
if(rv)
{
printf("SQL error!:%s\n",z_err_msg);//打印錯誤信息
sqlite3_free(z_err_msg);//用於釋放從內存中獲取的錯誤信息字符串
}
else
{
printf("select table successfully!\n");
}
sqlite3_close(db);//關閉數據庫
return 0;
}
-
編譯運行
咦?我們會發現一個問題,前面連接數據庫、創建表、插入數據例程中都有設置回調函數,但是都沒有被調用,這裏查詢記錄卻調用了四次,這是什麼原因呢?回調函數,專門用來處理查詢記錄的結果,比如在這裏,roommates表中一共有四條記錄,所以回調函數被調用了四次,每次調用輸出一條記錄,像連接數據庫、創建表、插入數據例程中不需要回調函數可以直接傳參NULL。回調函數原型如下:
這裏我想再進一步解釋一下columnValue和columnName這兩個二級指針,其餘兩個參數在上面程序中有說明。
printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");
col_name、col_value:表示一個二級指針,也就是存放指針的數組。col_name表示存放字段的地址,
col_value表示字段下面的值的地址。
col_name[i]、col_value[i]:表示一個一級指針,col_name[i]表示存放字段字符串的首地址,
col_value[i]表示存放字段下面值字符串的地址。因爲字段和值都是字符串。
typedef int (*sqlite_callback)(void* para,int columnCount,char** columnValue,char** columnName);
5、刪除表中所有記錄
c語言實現刪除上面例程插入roommates表中的數據。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sqlite3.h>
/*
功能:查詢記錄回調函數
參數:
para:由exec傳入的參數
col_num:查詢出一條記錄有多少個表頭
col_value:查詢出的記錄緩存區
col_name:表示字段的段命
返回:
成功返回0
失敗返回-1
*/
static int callback(void *para, int col_num, char **col_value, char **col_name)
{
int i;
printf("%s\n",(char*)para);
for(i = 0; i < col_num; i++)
{
printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");
}
printf("\n");
return 0;
}
int main(int argc, char **argv)
{
sqlite3 *db;//定義數據庫操作句柄
int rv;//返回值
char *sql;//SQL語句指針
char *z_err_msg;//獲取錯誤信息
char *data = "callback is called:";
rv = sqlite3_open("test.db",&db);//打開數據庫
if(rv)
{
printf("Can't open database!:%s\n",sqlite3_errmsg(db));
exit(0);
}
printf("Opening database successfully!\n");
//製作SQL語句
sql = "delete from roommates";
rv = sqlite3_exec(db,sql,callback,(void *)data,&z_err_msg);//執行sql語句
if(rv)
{
printf("SQL error!:%s\n",z_err_msg);//打印錯誤信息
sqlite3_free(z_err_msg);//用於釋放從內存中獲取的錯誤信息字符串
}
else
{
printf("delete recodes successfully!\n");
}
sqlite3_close(db);//關閉數據庫
return 0;
}
- 編譯運行
- 再次查看錶中是否有數據存在
從圖中可以看出roommates表中已經沒有數據存在了。
總結一下
從以上的五個例程中可以看出,sqlite數據庫最重要的三大API接口分別是sqlite3_open、sqlite3_exec、sqlite3_close。這三個函數就可以輕鬆操作sqlite數據庫,只需要將SQL語句換成相應的操作語句就ok,簡單易行,沒有複雜可言,當然在這裏我只是演示一下sqlite功能中的冰山一角,還有很多很多的數據庫操作沒有去實現,讓我一時間實現一遍也不可能,只能在以後的項目實踐中慢慢探索,仔細深挖。