iOS開發之FMDB
sqlite作為一個輕量級的資料庫,由於它佔用的記憶體很少,因此在很多的嵌入式裝置中得到廣泛的使用。iOS的SDK很早就開始支援了SQLite,我們只需要加入 libsqlite3.dylib 以及引入 sqlite3.h 標頭檔即可,但由於原生sqlite的API不是很友好,因此使用的話一般會對其做一層封裝,其中以開源的FMDB最為流行。 FMDB主要的類1.FMDatabase – 表示一個單獨的SQLite資料庫。 用來執行SQLite的命令。 2.FMResultSet – 表示FMDatabase執行查詢後結果集 3.FMDatabaseQueue – 當你在多線程中執行操作,使用該類能確保安全執行緒。 FMDB的使用資料庫的建立: 建立FMDatabase對象時需要參數為SQLite資料庫檔案路徑。該路徑可以是以下三種之一: 1..檔案路徑。該檔案路徑無需真實存,如果不存在會自動建立。 2..Null 字元串(@”")。表示會在臨時目錄建立一個臨時資料庫,當FMDatabase 連結關閉時,檔案也被刪除。 3.NULL. 將建立一個記憶體資料庫。同樣的,當FMDatabase串連關閉時,資料會被銷毀。 記憶體資料庫: 通常資料庫是存放在磁碟當中的。然而我們也可以讓存放在記憶體當中的資料庫,記憶體資料庫的優點是對其操作的速度較快,畢竟訪問記憶體的耗時低於訪問磁碟,但記憶體資料庫有如下缺陷:由於記憶體資料庫沒有被持久化,當該資料庫被關閉後就會立刻消失,斷電或程式崩潰都會導致資料丟失;不支援讀寫互斥處理,需要自己手動添加鎖;無法被別的進程訪問。 臨時資料庫: 臨時資料庫和記憶體資料庫非常相似,兩個資料庫連接建立的臨時資料庫也是各自獨立的,在串連關閉後,臨時資料庫將自動消失,其底層檔案也將被自動刪除。儘管磁碟檔案被建立用於儲存臨時資料庫中的資料資訊,但是實際上臨時資料庫也會和記憶體資料庫一樣通常駐留在記憶體中,唯一不同的是,當臨時資料庫中資料量過大時,SQLite為了保證有更多的記憶體可用於其它操作,因此會將臨時資料庫中的部分資料寫到磁碟檔案中,而記憶體資料庫則始終會將資料存放在記憶體中。 建立資料庫:FMDatabase *db= [FMDatabase databaseWithPath:dbPath] ; 在進行資料庫的操作之前,必須要先把資料庫開啟,如果資源或許可權不足無法開啟或建立資料庫,都會導致開啟失敗。 如下為建立和開啟資料庫的樣本: 複製代碼NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);NSString *documentDirectory = [paths objectAtIndex:0]; //dbPath: 資料庫路徑,存放在Document中。NSString *dbPath = [documentDirectory stringByAppendingPathComponent:@"MYTest.db"]; //建立資料庫執行個體 db 這裡說明下:如果路徑中不存在"MYTest.db"的檔案,sqlite會自動建立"MYTest.db"FMDatabase *db= [FMDatabase databaseWithPath:dbPath] ;if (![db open]) {NSLog(@"Could not open db.");return ;}複製代碼 更新操作 一切不是SELECT命令都視為更新操作,包括CREATE, UPDATE, INSERT,ALTER,COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM和REPLACE等。 建立表: [db executeUpdate:@"CREATE TABLE myTable (Name text,Age integer)"]; 插入 [db executeUpdate:@"INSERT INTO myTable (Name,Age) VALUES (?,?)",@"jason",[NSNumber numberWithInt:20]]; 更新 [db executeUpdate:@"UPDATE myTable SET Name = ? WHERE Name = ? ",@"john",@"jason"];. 刪除 [db executeUpdate:@"DELETE FROM myTable WHERE Name = ?",@"jason"]; 查詢操作 SELECT命令就是查詢,執行查詢的方法是以 -excuteQuery開頭的。執行查詢時,如果成功返回FMResultSet對象, 錯誤返回nil. 讀取資訊的時候需要用while迴圈: FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"]; while ([s next]) { //從每條記錄中提取資訊 } 關閉資料庫 當使用完資料庫,你應該 -close 來關閉資料庫連接來釋放SQLite使用的資源。 [db close]; 參數 通常情況下,你可以按照標準的SQL語句,用?表示執行語句的參數,如: INSERT INTO myTable VALUES (?, ?, ?) 然後,可以我們可以調用executeUpdate方法來將?所指代的具體參數傳入,通常是用變長參數來傳遞進去的,如下: NSString *sql = @"insert into myTable (name, password) values (?, ?)";[db executeUpdate:sql, user.name, user.password];這裡需要注意的是,參數必須是NSObject的子類,所以象int,double,bool這種基本類型,需要進行相應的封裝 [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]]; 多線程操作 由於FMDatabase對象本身不是安全執行緒的,因此為了避免在多線程操作的時候出錯,需要使用 FMDatabaseQueue來執行相關操作。只需要利用一個資料庫檔案地址來初使化FMDatabaseQueue,然後傳入一個block到inDatabase中,即使是多個線程同時操作,該queue也會確保這些操作能按序進行,保證安全執行緒。 建立隊列: FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; 使用方法: 複製代碼[queue inDatabase:^(FMDatabase *db) { [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; FMResultSet *rs = [db executeQuery:@"select * from foo"]; while([rs next]) { … } }]; 複製代碼至於事務可以像這樣處理: 複製代碼[queue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; if (somethingWrongHappened) { *rollback = YES; return; } // etc… [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; }];