最近開始寫博客了,把我學習到的東西進行匯總和總結,今天就說說怎么使用sqlite3來操縱數據庫吧
數據庫的相關知識我就不去說明了,畢竟只要會sql語言的人就大家都一樣。
本案例是在Xcode環境下創建的single view application進行演示操作,如有不清楚的朋友可以找我下載代碼。qq:1750587828.
首先第一點,為什么要使用sqlite3?
在iOS的編程中,毫無疑問接觸最多的就是界面的代碼編排和設計,數據的解析與放置,算法的各種撓頭問題。。。 在數據的解析與放置這一塊,就會涉及到數據庫緩存的操作,我們都知道,iOS手機編程是在手機端運行的,你不能老是去服務器端讀取數據啊,好,就算你不煩,手機也跑的起來,流量不要過啊,對於手機控或者應用使用者來說,流量就是生命,而且,如果總是去服務器端讀取數據,對手機的運行速度也會有影響,畢竟有一個網絡傳輸的過程,所以,為了讓用戶有一個更好的體驗,一般建議的做法是,將服務器的數據進行下載,然后通過數據庫緩存起來,這樣就不用每次每次的去請求服務器數據了,如果在數據庫中有的數據,直接可以通過數據庫查詢得到,而省去了一次甚至多次的服務器請求操作。而sqlite3就是提供了一種C語言的訪問數據庫的形式。之后我們的代碼會看到,其實sqlite3的語法可能比較難以理解,不過,我也會給大家來進行介紹的。
那么第二點,使用sqlite3的好處是什么?
使用sqlite3的好處么,除開語法的各種蛋疼之外,訪問的速度還是會比FMDB快一些的。而且,隨着一步步的匯總和總結,你可以清晰的知道每一句sqlite3的語句的作用,而不是使用封裝好了的語句,只要用就可以了,但是不知道是為什么。我個人覺得,學習學習吧,還是要知其然,亦知其所以然這樣才能學的踏實。
第三點,讓我們來開始學習sqlite3的使用方式吧:
3.1 第一步,引入sqlite3庫,並在使用sqlite3的地方導入sqlite3.
3.2 第二步,創建sqlite數據庫文件
sqlite3提供的是一種訪問操縱數據庫的形式,那么,如果想要使用sqlite3來訪問操縱數據庫,首先我們得先有個數據庫,下面就是一句代碼生成一個數據庫文件。
/*得到數據庫文件地址,這是一個拼接的地址字符串,是沙盒路徑下面的shop.sqlite文件,
這個文件名可以隨便取名字,后綴最好是db啊或者sqlite這種,用來表示這是一個數據庫文件*/
NSString* filename=[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"shop.sqlite"];
/*sqlite3_open是我們接觸到的第一條sqlite3語句,它的作用時打開數據庫連接,如果有數據庫文件就打開它,沒有就重新創建數據庫,這個方法有一個枚舉的返回值表示是否正常打開了數據庫,我用int的變量status去接收了這個值,后面會進行判斷。
sqlite3_open有兩個參數,第一個參數是數據庫文件的路徑,第二個參數是一個數據庫的引用,即一個sqlite3*類型的引用;
filename.UTF8String:filename本身是oc的字符串類型,但是sqlite3_open要求傳遞的是C類型的字符串,所以,使用UTF8String將oc的字符串類型轉換為C類型的字符串
*/
int status=sqlite3_open(filename.UTF8String, &_shop);
if(status == SQLITE_OK)//枚舉值SQLITE_OK,代表成功的狀態
{
NSLog(@"打開數據庫成功");
}
else
NSLog(@"打開數據庫失敗");
3.3 創建數據庫表
當我們打開了數據庫連接的時候,表示在程序的沙盒路徑下已經創建了一個shop.sqlite的數據庫文件,而這個數據庫里現在什么東西都沒有,我們需要創建一張數據庫表來存放數據。在這里我就封裝一個setupTable來進行創建表的操作。
-(void) setupTable
{
//創表語句,IF NOT EXISTS防止創建重復的表,AUTOINCREMENT是自動增長關鍵字,real是數字類型
const char * sql="CREATE TABLE IF NOT EXISTS t_shop(id integer PRIMARY KEY AUTOINCREMENT,name text NOT NULL,price real);";
//保存錯誤信息的變量
char * errMsg=NULL;
/*sqlite3_exec是我們接觸到的第二個sqlite3語句,這個語句用於執行除了查詢語句以外的其他語句.
它有一個枚舉類型的返回值,和sqlite3_open返回的枚舉值一致,這里我並沒有使用變量保存,因為我有其他形式來獲得創建表是否成功。
sqlite3_exec需要傳遞5個參數,第一個參數是數據庫引用即sqlite3* _shop,第二個參數是要執行的sql語句,
第三個參數是執行完sql語句后要執行的函數,第四個參數是執行完sql語句后要執行的函數的參數,第五個參數是執行完sql語句后的報錯信息。
*/
sqlite3_exec(_shop, sql, NULL, NULL, &errMsg);
if(errMsg)//如果存在報錯信息,代表語句執行失敗,比判斷枚舉值要更簡單一些
{
NSLog(@"創建表shop失敗-%s",errMsg);//打印錯誤信息
}
}
3.4 封裝數據庫連接和創建數據庫表
-(void)setupDB
{
//得到數據庫文件地址
NSString* filename=[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"shop.sqlite"];
//NSLog(@"%@",filename);
//打開數據庫連接,如果有就打開,沒有就重新創建連接
int status=sqlite3_open(filename.UTF8String, &_shop);
if(status == SQLITE_OK)
{
NSLog(@"打開數據庫成功");
//創表語句
[self setupTable];
}
else
{
NSLog(@"打開數據庫失敗");
}
}
3.5 數據表操縱
所謂的數據表操縱即是對數據表中數據的增刪改,也是最經常會使用到的功能。即執行insert,update,delete語句。
- (IBAction)add:(id)sender {//這里是一個按鈕的點擊提供的新增功能
/*拼接插入數據的sql語句*/
NSString * sql=[NSString stringWithFormat:@"INSERT INTO t_shop(name,price) VALUES('%@',%f)",self.name.text,self.price.text.doubleValue];
char* errMsg=NULL;
sqlite3_exec(self.shop, sql.UTF8String, NULL, NULL, &errMsg);
if(errMsg)
{
NSLog(@"插入數據失敗--%s",errMsg);
}
}
-(void)updateData//這里是一個方法提供了更新功能
{
//拼接sql更新語句
NSString * sql=[NSString stringWithFormat:@"update t_shop set name='%@',price='%@' where id=%@",self.name.text,self.price.text,self.lbl.text];
//NSLog(@"%@",sql);
char* errMsg=NULL;
sqlite3_exec(self.myShop, sql.UTF8String, NULL, NULL, &errMsg);
if(errMsg)
{
NSLog(@"更新數據失敗--%s",errMsg);
}
}
-(void)deleteDataById:(int)pid
{//提供一個方法執行刪除操作,該方法要求得到要刪除的數據的id
//拼接sql刪除語句
NSString * sql=[NSString stringWithFormat:@"DELETE FROM t_shop where id=%d",pid];
char* errMsg=NULL;
sqlite3_exec(self.shop, sql.UTF8String, NULL, NULL, &errMsg);
if(errMsg)
{
NSLog(@"刪除數據失敗--%s",errMsg);
}
}
大家可以觀察上面的三個方法,會發現除了sql語句的拼接不一樣以外,其他的地方幾乎一模一樣,所以,增刪改的操作相對來說還是比較簡單的。
3.6 查詢數據
/**
* 查詢數據
*/
-(void)setupData
{
const char * sql="select * from t_shop";//查詢sql語句
//stmt用來取出查詢結果
sqlite3_stmt *stmt=NULL;
/*sqlite3_prepare_v2函數是准備要執行sql查詢的一個函數,可以當做這個函數就是用來做sql查詢之前的准備工作的,
它也是返回一個枚舉作為准備工作的結果,SQLITE_OK則代表准備工作ok
sqlite3_prepare_v2需要傳入5個參數,第一個參數是數據庫引用即(sqlite3* _shop),第二個參數是要執行的sql語句,第三個參數是sql語句的長度
第四個參數是查詢結果stmt的引用,查詢完成后,查詢結果將會存入該引用,第五個參數是指向無法使用的部分的指針,一般不會用到,給NULL就可以了
*/
int status = sqlite3_prepare_v2(_shop, sql, -1, &stmt, NULL);
if(status == SQLITE_OK)//准備成功,SQL語句正確
{
/*sqlite3_step(stmt)函數將會執行查詢並且將查詢到的當前記錄存入到stmt(sqlite3_stmt * 類型)中
第一次執行sqlite3_step(stmt)將會將表中的第一條數據存入到stmt中,第二次執行sqlite3_step(stmt)將會把表中的第二條記錄存入到stmt中
也就是說,while(sqlite3_step(stmt)==SQLITE_ROW)將會一條一條的去讀取表中的記錄,而SQLITE_ROW枚舉判斷的是有讀取到數據行的情況*/
while(sqlite3_step(stmt) == SQLITE_ROW)//成功指向一條記錄
{
Shop* shop=[[Shop alloc]init];//封裝的實體
/*sqlite3_column_xxxx函數:它用來讀取數據行中不同類型的數據,該函數的返回值就是讀取到得數據內容,
該函數需要2個參數,第一個參數是存放數據的stmt,第二個參數是數據列下標*/
shop.pid= sqlite3_column_int(stmt, 0);//讀取stmt中存儲的第0列數據
const char* pname= (const char*)sqlite3_column_text(stmt, 1);//讀取stmt中存儲的第1列數據
const char* pprice = (const char*)sqlite3_column_text(stmt, 2);//讀取stmt中存儲的第2列數據
shop.name = [NSString stringWithUTF8String:pname];//將C類型的字符串轉換為oc類型的字符串並存儲
shop.price = [NSString stringWithUTF8String:pprice];//將C類型的字符串轉換為oc類型的字符串並存儲
//NSLog(@"編號:%d,商品名:%s,價格:%s",shop.pid,pname,pprice);
}
}
}
那么,寫到這里,相信大家對sqlite3的基本使用已經有了大致的了解,如果對代碼中有不理解的地方,或者有其他相關的問題,可以找我一起來研究討論。
第一次發博客,希望大家提出寶貴的意見和建議,編程路上,與你同行。