摘要 IOS操作數(shù)據(jù)庫(kù),SQLite3和coredata是兩個(gè)非常好的選擇,但是對(duì)于我們這些掌握了其他數(shù)據(jù)庫(kù)語(yǔ)言的人來(lái)說(shuō),使用這兩中操作都會(huì)覺(jué)得不方便,SQLite3使用起來(lái)太復(fù)雜了,而使用coredata的時(shí)候卻封裝太死了,我們需要自己些自己的數(shù)據(jù)庫(kù)語(yǔ)句,這時(shí)候,F(xiàn)MDB就是一個(gè)非常不錯(cuò)的選擇!
FMDB 詳解
什么是FMDB
FMDB是iOS平臺(tái)的SQLite數(shù)據(jù)庫(kù)框架
FMDB以O(shè)C的方式封裝了SQLite的C語(yǔ)言API
FMDB的優(yōu)點(diǎn)
使用起來(lái)更加面向?qū)ο螅∪チ撕芏嗦闊⑷哂嗟腃語(yǔ)言代碼
對(duì)比蘋果自帶的Core Data框架,更加輕量級(jí)和靈活
提供了多線程安全的數(shù)據(jù)庫(kù)操作方法,有效地防止數(shù)據(jù)混亂
FMDB的github地址
https://github.com/ccgus/fmdb
廢話少說(shuō),下面來(lái)介紹FMDB的使用吧
FMDB有三個(gè)主要的類
FMDatabase
一個(gè)FMDatabase對(duì)象就代表一個(gè)單獨(dú)的SQLite數(shù)據(jù)庫(kù)
用來(lái)執(zhí)行SQL語(yǔ)句
FMResultSet
使用FMDatabase執(zhí)行查詢后的結(jié)果集
FMDatabaseQueue
用于在多線程中執(zhí)行多個(gè)查詢或更新,它是線程安全的
下面來(lái)打開(kāi)數(shù)據(jù)庫(kù) ,一般都需要數(shù)據(jù)庫(kù)的路徑地址:path
通過(guò)指定SQLite數(shù)據(jù)庫(kù)文件路徑來(lái)創(chuàng)建FMDatabase對(duì)象
FMDatabase *db = [FMDatabase databaseWithPath:path];
if (![db open]) {
NSLog(@"數(shù)據(jù)庫(kù)打開(kāi)失敗!");
}
path文件路徑有三種情況
1,具體文件路徑
如果不存在會(huì)自動(dòng)創(chuàng)建
2,空字符串@“”
會(huì)在臨時(shí)目錄創(chuàng)建一個(gè)空的數(shù)據(jù)庫(kù)
當(dāng)FMDatabase連接關(guān)閉時(shí),數(shù)據(jù)庫(kù)文件也被刪除
3,nil
會(huì)創(chuàng)建一個(gè)內(nèi)存中臨時(shí)數(shù)據(jù)庫(kù),當(dāng)FMDatabase連接關(guān)閉時(shí),數(shù)據(jù)庫(kù)會(huì)被銷毀
CURD操作:
在FMDB中,除查詢以外的所有操作,都稱為“更新”
create、drop、insert、update、delete等
使用executeUpdate:方法執(zhí)行更新
(BOOL)executeUpdate:(NSString)sql, …
(BOOL)executeUpdateWithFormat:(NSString)format, …
(BOOL)executeUpdate:(NSString)sql withArgumentsInArray:(NSArray )arguments
示例
[db executeUpdate:@“UPDATE t_student SET age = ? WHERE name = ?;“, @20, @“Jack”]
查詢方法
(FMResultSet )executeQuery:(NSString)sql, …
(FMResultSet )executeQueryWithFormat:(NSString)format, …
(FMResultSet )executeQuery:(NSString )sql withArgumentsInArray:(NSArray *)arguments
示例
// 查詢數(shù)據(jù)
FMResultSet *rs = [db executeQuery:@“SELECT * FROM t_student”];
// 遍歷結(jié)果集
while ([rs next]) {
NSString *name = [rs stringForColumn:@"name"];
int age = [rs intForColumn:@"age"];
double score = [rs doubleForColumn:@"score"];
}
多線程管理FMDB
FMDatabase這個(gè)類是線程不安全的,如果在多個(gè)線程中同時(shí)使用一個(gè)FMDatabase實(shí)例,會(huì)造成數(shù)據(jù)混亂等問(wèn)題
為了保證線程安全,F(xiàn)MDB提供方便快捷的FMDatabaseQueue類
FMDatabaseQueue的創(chuàng)建
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
簡(jiǎn)單使用
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];
FMResultSet *rs = [db executeQuery:@"select * from t_student"];
while ([rs next]) {
// …
}
}];
使用事務(wù)
[queue inTransaction:^(FMDatabase db, BOOL rollback) {
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];
FMResultSet *rs = [db executeQuery:@"select * from t_student"];
while ([rs next]) {
// …
}
}];
事務(wù)回滾
*rollback = YES;
-開(kāi)啟/關(guān)閉資料庫(kù)
使用資料庫(kù)的第一件事,就是建立一個(gè)資料庫(kù)。要注意的是,在iOS環(huán)境下,只有document directory 是可以進(jìn)行讀寫(xiě)的。在寫(xiě)程式時(shí)用的那個(gè)Resource資料夾底下的東西都是read-only。因此,建立的資料庫(kù)要放在document 資料夾下。方法如下:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentDirectory stringByAppendingPathComponent:@"MyDatabase.db"];
FMDatabase
*db = [FMDatabase databaseWithPath:dbPath] ;
if (![db open]) {
NSLog(@“Could not open db.”);
return ;
}
通常這段程式碼會(huì)放在UIViewController中viewDidLoad的函式里。指定路徑后,用[FMDatabase databaseWithPath:]回傳一個(gè)FMDatabase物件,如果該路徑本來(lái)沒(méi)有檔案,會(huì)新增檔案,不然會(huì)開(kāi)啟舊檔。最后呼叫[db open]可以開(kāi)啟該資料庫(kù)檔案,[db close]則關(guān)閉該檔案。
-建立table
如果是新建的資料庫(kù)檔,一開(kāi)始是沒(méi)有table的。建立table的方式很簡(jiǎn)單:
[db executeUpdate:@"CREATE TABLE PersonList (Name text, Age integer, Sex integer, Phone text, Address text, Photo blob)"];
這是FMDB里很常用的指令,[ FMDatabase_object executeUpdate:]后面用NSString塞入SQLite語(yǔ)法,就解決了。因?yàn)檫@篇主要是在講FMDB,所以SQLite的語(yǔ)法就不多說(shuō)了,上述程式碼建立了一個(gè)名為PersonList的table,里面有姓名、年齡、性別、電話、地址和照片。(嗯….很范例的一個(gè)table)
-插入資料
插入資料跟前面一樣,用executeUpdate后面加語(yǔ)法就可以了。比較不同的是,因?yàn)椴迦氲馁Y料會(huì)跟Objective-C的變數(shù)有關(guān),所以在string里使用?號(hào)來(lái)代表這些變數(shù)。
[db executeUpdate:@"INSERT INTO PersonList (Name, Age, Sex, Phone, Address, Photo) VALUES (?,?,?,?,?,?)",
@"Jone", [NSNumber numberWithInt:20], [NSNumber numberWithInt:0], @“091234567”, @“Taiwan, ROC”, [NSData dataWithContentsOfFile:? filepath ]];
其中,在SQLite中的text對(duì)應(yīng)到的是NSString,integer對(duì)應(yīng)NSNumber,blob則是NSData。該做的轉(zhuǎn)換FMDB都做好了,只要了解SQLite語(yǔ)法,應(yīng)該沒(méi)有什么問(wèn)題才是。
-更新資料
太簡(jiǎn)單了,不想講,請(qǐng)看范例:
[db executeUpdate:@"UPDATE PersonList SET Age = ? WHERE Name = ?",[NSNumber numberWithInt:30],@“John”];
-取得資料
取得特定的資料,則需使用FMResultSet物件接收傳回的內(nèi)容:
FMResultSet *rs = [db executeQuery:@"SELECT Name, org.apache.jasper.JasperException: For input stringAge, FROM PersonList"];
while ([rs next]) {
NSString *name = [rs stringForColumn:@"Name"];
int age = [rs intForColumn:@"Age"];
}
[rs close];
用[rs next]可以輪詢query回來(lái)的資料,每一次的next可以得到一個(gè)row里對(duì)應(yīng)的數(shù)值,并用[rs stringForColumn:]或[rs intForColumn:]等方法把值轉(zhuǎn)成Object-C的型態(tài)。取用完資料后則用[rs close]把結(jié)果關(guān)閉。
-快速取得資料
在有些時(shí)候,只會(huì)query某一個(gè)row里特定的一個(gè)數(shù)值(比方只是要找John的年齡),F(xiàn)MDB提供了幾個(gè)比較簡(jiǎn)便的方法。這些方法定義在FMDatabaseAdditions.h,如果要使用,記得先import進(jìn)來(lái)。
//找地址
NSString *address = [db stringForQuery:@"SELECT Address FROM PersonList WHERE Name = ?",@"John”];
//找年齡
int age = [db intForQuery:@"SELECT Age FROM PersonList WHERE Name = ?",@"John”];