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