初識FMDB
iOS中原生的SQLiteAPI在進(jìn)行數(shù)據(jù)存儲的時候缤骨,需要使用C語言中的函數(shù)爱咬,操作比較麻煩。于是绊起,就出現(xiàn)了一系列將SQLite API進(jìn)行封裝的庫精拟,例如FMDB、PlausibleDatabase虱歪、sqlitepersistentobjects等蜂绎。
FMDB是一款簡潔、易用的封裝庫笋鄙。因此师枣,在這里推薦使用第三方框架FMDB,它是對libsqlite3框架的封裝萧落,用起來的步驟與SQLite使用類似践美,并且它對于多線程的并發(fā)操作進(jìn)行了處理劳殖,所以是線程安全的。
FMDB PK Sqlite
優(yōu)點(diǎn):
對多線程的并發(fā)操作進(jìn)行處理拨脉,所以是線程安全的哆姻;
以O(shè)C的方式封裝了SQLite的C語言API,使用起來更加的方便玫膀;
FMDB是輕量級的框架矛缨,使用靈活。
缺點(diǎn):
因為它是OC的語言封裝的帖旨,只能在ios開發(fā)的時候使用箕昭,所以在實(shí)現(xiàn)跨平臺操作的時候存在局限性。
FMDB框架中重要的框架類
FMDatabase
FMDatabase對象就代表一個單獨(dú)的SQLite數(shù)據(jù)庫解阅,用來執(zhí)行SQL語句
FMResultSet
使用FMDatabase執(zhí)行查詢后的結(jié)果集
FMDatabaseQueue
用于在多線程中執(zhí)行多個查詢或更新落竹,它是線程安全的
FMDB使用步驟
下載FMDB文件GitHub,并將FMDB文件夾添加到項目中(也可使用CocoaPods導(dǎo)入)
導(dǎo)入libsqlite3.0框架,導(dǎo)入頭文件FMDatabase.h
代碼實(shí)現(xiàn)货抄,與SQLite使用步驟相似述召,創(chuàng)建數(shù)據(jù)庫路徑,獲得數(shù)據(jù)庫路徑蟹地,打開數(shù)據(jù)庫积暖,然后對數(shù)據(jù)庫進(jìn)行增、刪怪与、改夺刑、查操作,最后關(guān)閉數(shù)據(jù)庫分别。
step.png
數(shù)據(jù)庫創(chuàng)建
創(chuàng)建FMDatabase對象時參數(shù)為SQLite數(shù)據(jù)庫文件路徑遍愿,該路徑可以是以下三種方式之一
文件路徑。該文件路徑無需真實(shí)存在耘斩,如果不存在會自動創(chuàng)建
空字符串(@“”)沼填。表示會在臨時目錄創(chuàng)建一個空的數(shù)據(jù)庫,當(dāng)FMDatabase連接關(guān)閉時煌往,文件也會被刪除
NULL倾哺。將創(chuàng)建一個內(nèi)在數(shù)據(jù)庫,同樣的刽脖,當(dāng)FMDatabase連接關(guān)閉時,數(shù)據(jù)將會被銷毀
本文中使用的測試模型類.h
student.png
數(shù)據(jù)庫使用FMDB框架代碼操作
使用FMDataBase類建立數(shù)據(jù)庫
//1.獲得數(shù)據(jù)庫文件的路徑
NSString*doc =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)? lastObject];
NSString*fileName = [doc stringByAppendingPathComponent:@“student.sqlite”];
//2.獲得數(shù)據(jù)庫
FMDatabase *db = [FMDatabase databaseWithPath:fileName];
//3.使用如下語句忌愚,如果打開失敗曲管,可能是權(quán)限不足或者資源不足。通常打開完操作操作后硕糊,需要調(diào)用 close 方法來關(guān)閉數(shù)據(jù)庫院水。在和數(shù)據(jù)庫交互 之前腊徙,數(shù)據(jù)庫必須是打開的。如果資源或權(quán)限不足無法打開或創(chuàng)建數(shù)據(jù)庫檬某,都會導(dǎo)致打開失敗撬腾。
if([db open])
{
//4.創(chuàng)表
BOOLresult = [db executeUpdate:@“CREATE TABLE IF NOT EXISTS t_student (idinteger PRIMARY KEY AUTOINCREM ENT, name text NOTNULL, age integer NOTNULL);”];
if(result)
{
NSLog(@“創(chuàng)建表成功”);
}
}
查看sql表
根據(jù)路徑fileName在Finder中搜索.sqlite文件,并復(fù)制到桌面
使用火狐瀏覽器工具下的SQLite Manager打開.sqlite文件
2.png
數(shù)據(jù)表結(jié)構(gòu)
sql.png
使用FMDataBase類執(zhí)行數(shù)據(jù)庫命令SQL
一切不是SELECT命令的命令都視為更新恢恼。這包括 CREAT,UPDATE,INSERT,ALTER,BEGIN,COMMIT,DETACH,DELETE,DROP,END,EXPLAIN,VACUUM,REPLACE等民傻。
簡單來說,只要不是以SELECT開頭的命令都是更新命令场斑。
執(zhí)行更新返回一個BOOL值漓踢。YES表示 執(zhí)行成功,否則表示有錯誤漏隐。你可以調(diào)用 -lastErrorMessage 和 -lastErrorCode方法來得到更多信息喧半。
使用FMDataBase類執(zhí)行數(shù)據(jù)庫插入命令SQLinsert into
int age = 42;
//1.executeUpdate:不確定的參數(shù)用?來占位(后面參數(shù)必須是oc對象青责,挺据;代表語句結(jié)束)
[self.db executeUpdate:@“INSERTINTOt_student (name, age)VALUES(?,?);”,name,@(age)];
//2.executeUpdateWithForamat:不確定的參數(shù)用%@,%d等來占位 (參數(shù)為原始數(shù)據(jù)類型脖隶,執(zhí)行語句不區(qū)分大小寫)
[self.db executeUpdateWithForamat:@“insertintot_student (name,age)values(%@,%i);”,name,age];
//3.參數(shù)是數(shù)組的使用方式
[self.db executeUpdate:@“INSERTINTO
t_student(name,age)VALUES(?,?);”withArgumentsInArray:@[name,@(age????????????? )]];
使用FMDataBase類執(zhí)行數(shù)據(jù)庫刪除命令SQLdelete
//1.不確定的參數(shù)用吴菠?來占位 (后面參數(shù)必須是oc對象,需要將int包裝成OC對象)
intidNum =101;
[self.db executeUpdate:@“deletefrom t_student where id = ?;”,@(idNum)];
//2.不確定的參數(shù)用%@,%d等來占位
[self.db executeUpdateWithFormat:@“deletefrom t_student where name = %@;”,@“apple_name”];
使用FMDataBase類執(zhí)行數(shù)據(jù)庫修改命令SQLupdate
//修改學(xué)生的名字
[self.db executeUpdate:@“updatet_studentsetname= ?wherename= ?”,newName,oldName];
使用FMDataBase類執(zhí)行數(shù)據(jù)庫查詢命令SQLselect ... from
SELECT命令就是查詢浩村,執(zhí)行查詢的方法是以-excuteQuery開頭的做葵。
執(zhí)行查詢時,如果成功返回FMResultSet對象心墅,錯誤返回nil酿矢。與執(zhí)行更新相當(dāng),支持使用NSError參數(shù)怎燥。
同時瘫筐,你也可以使用-lastErrorCode和-lastErrorMessage獲知錯誤信息。
FMResultSet獲取不同數(shù)據(jù)格式的方法
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnIndex:
objectForColumn:
使用FMResultSet獲取查詢語句結(jié)果
//查詢整個表
FMResultSet *resultSet = [self.db execute Query:@“select* from t_student;”];
//根據(jù)條件查詢
FMResultSet *resultSet = [self.db executeQuery:@“select* from t_student where id
//遍歷結(jié)果集合
while([resultSet? next])
{
intidNum = [resultSet intForColumn:@“id”]铐姚;
NSString *name = [resultSet
objectForColumn:@“name”];
intage = [resultSet intForColumn:@“age”];
}
使用FMDataBase類執(zhí)行數(shù)據(jù)庫銷毀命令SQLdrop ...
//如果表格存在 則銷毀
[self.db executeUpadate:@“droptableifexistst_student;”];
使用FMDatabaseQueue類實(shí)現(xiàn)多線程操作
在多個線程中同時使用一個FMDatabase實(shí)例是不明智的〔吒危現(xiàn)在你可以為每 個線程創(chuàng)建一個FMDatabase對象,不要讓多個線程分享同一個實(shí)例隐绵,他無 法在多個線程中同事使用之众。否則程序會時不時崩潰或者報告異常。所以依许,不要 初始化FMDatabase對象棺禾,然后在多個線程中使用。這時候峭跳,我們就需要使 用FMDatabaseQueue來創(chuàng)建隊列執(zhí)行事務(wù)膘婶。
//1.創(chuàng)建隊列
FMDatabaseQueue *queue = [FMDatabaseQueue
databaseQueueWithPath:aPath];
__block BOOL whoopsSomethingWrongHappened =true;
//2.把任務(wù)包裝到事務(wù)里
[queueinTransaction:^(FMDatabase *db, BOOL *rollback)
{
whoopsSomethingWrongHappened &=? [dbexecuteUpdate:@“INSERT INTO myTable VALUES (?)”,???? [NSNumber numberWith:1]];
whoopsSomethingWrongHappened &= [db
executeUpdata:@“INSERT INTO myTable VALUES (?)”,
[NSNumber numberWithInt:2]];
whoopsSomethingWrongHappened &= [db
executeUpdata:@“INSERT INTO myTable VALUES (?)”[NSNumber
numberWithInt:3]];
//如果有錯誤 返回
if(!whoopsSomethingWrongHappened)
{
*rollback = YES;
return;
}
}];
自己測試: