上一節我已經介紹了SQLite的簡單使用,不瞭解的能夠提早去看一下iOS學習筆記16-數據庫SQLite,這節咱們來說下FMDB。html
FMDB是一種第三方的開源庫,FMDB就是對SQLite的API進行了封裝,加上了面向對象的思想,讓咱們沒必要使用繁瑣的C語言API函數,比起直接操做SQLite更加方便。git
由於是OC語言封裝的,失去了SQLite原來的跨平臺性github
libsqlite3
庫的依賴#import
導入FMDB的頭文件"FMDatabase.h"
FMDatabase
: 一個單一的SQLite數據庫,用於執行SQL語句。FMResultSet
:執行查詢一個FMDatabase結果集。FMDatabaseQueue
:在多個線程來執行查詢和更新時會使用這個類。FMDatabase
的類方法:/* 1. 若是該路徑下已經存在該數據庫,直接獲取該數據庫; 2. 若是不存在就建立一個新的數據庫; 3. 若是傳@"",會在臨時目錄建立一個空的數據庫,當數據庫關閉時,數據庫文件也被刪除; 4. 若是傳nil,會在內存中臨時建立一個空的數據庫,當數據庫關閉時,數據庫文件也被刪除; */ + (FMDatabase *)databaseWithPath:(NSString *)filePath;
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject; NSString *filePath = [path stringByAppendingPathComponent:@"FMDB.db"]; FMDatabase *database = [FMDatabase databaseWithPath:filePath];
注意:這裏建立數據庫,並不會打開數據庫,和SQLite有點區別sql
/* 打開數據庫,成功返回YES,失敗返回NO */ - (BOOL)open; /* 關閉數據庫,成功返回YES,失敗返回NO */ - (BOOL)close;
在FMDB中,除查詢之外的全部操做,都稱爲「更新」。
例如create
、drop
、insert
、update
、delete
等SQL語句命令都是更新操做。數據庫
/* 執行更新的SQL語句,字符串裏面的"?",依次用後面的參數替代,必須是對象,不能是int等基本類型 */ - (BOOL)executeUpdate:(NSString *)sql,... ; /* 執行更新的SQL語句,可使用字符串的格式化進行構建SQL語句 */ - (BOOL)executeUpdateWithFormat:(NSString*)format,... ; /* 執行更新的SQL語句,字符串中有"?",依次用arguments的元素替代 */ - (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments;
/* 1. 直接使用完整的SQL更新語句 */ [database executeUpdate:@"insert into mytable(num,name,sex) values(0,'liuting','m');"]; NSString *sql = @"insert into mytable(num,name,sex) values(?,?,?);"; /* 2. 使用不完整的SQL更新語句,裏面含有待定字符串"?",須要後面的參數進行替代 */ [database executeUpdate:sql,@0,@"liuting",@"m"]; /* 3. 使用不完整的SQL更新語句,裏面含有待定字符串"?",須要數組參數裏面的參數進行替代 */ [database executeUpdate:sql withArgumentsInArray:@[@0,@"liuting",@"m"]]; /* 4. SQL語句字符串可使用字符串格式化,這種咱們應該比較熟悉 */ [database executeUpdateWithFormat:@"insert into mytable(num,name,sex) values(%d,%@,%@);",0,@"liuting","m"];
- (BOOL)createTable { NSString *sqlStr = @"create table mytable(num integer,name varchar(7),sex char(1),primary key(num));"; BOOL res = [_database executeUpdate:sqlStr]; if (!res) { NSLog(@"error when creating database table"); [_database close]; } return res; }
查詢SQL語句通常指select
數組
/* 執行查詢SQL語句,返回FMResultSet查詢結果 */ - (FMResultSet *)executeQuery:(NSString*)sql, ... ; - (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... ; - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments;
/* 獲取下一個記錄 */ - (BOOL)next; /* 獲取記錄有多少列 */ - (int)columnCount; /* 經過列名獲得列序號,經過列序號獲得列名 */ - (int)columnIndexForName:(NSString *)columnName; - (NSString *)columnNameForIndex:(int)columnIdx; /* 獲取存儲的整形值 */ - (int)intForColumn:(NSString *)columnName; - (int)intForColumnIndex:(int)columnIdx; /* 獲取存儲的長整形值 */ - (long)longForColumn:(NSString *)columnName; - (long)longForColumnIndex:(int)columnIdx; /* 獲取存儲的布爾值 */ - (BOOL)boolForColumn:(NSString *)columnName; - (BOOL)boolForColumnIndex:(int)columnIdx; /* 獲取存儲的浮點值 */ - (double)doubleForColumn:(NSString *)columnName; - (double)doubleForColumnIndex:(int)columnIdx; /* 獲取存儲的字符串 */ - (NSString *)stringForColumn:(NSString *)columnName; - (NSString *)stringForColumnIndex:(int)columnIdx; /* 獲取存儲的日期數據 */ - (NSDate *)dateForColumn:(NSString *)columnName; - (NSDate *)dateForColumnIndex:(int)columnIdx; /* 獲取存儲的二進制數據 */ - (NSData *)dataForColumn:(NSString *)columnName; - (NSData *)dataForColumnIndex:(int)columnIdx; /* 獲取存儲的UTF8格式的C語言字符串 */ - (const unsigned cahr *)UTF8StringForColumnName:(NSString *)columnName; - (const unsigned cahr *)UTF8StringForColumnIndex:(int)columnIdx; /* 獲取存儲的對象,只能是NSNumber、NSString、NSData、NSNull */ - (id)objectForColumnName:(NSString *)columnName; - (id)objectForColumnIndex:(int)columnIdx;
- (NSArray *)getResultFromDatabase{ //執行查詢SQL語句,返回查詢結果 FMResultSet *result = [_database executeQuery:@"select * from mytable"]; NSMutableArray *array = [NSMutableArray array]; //獲取查詢結果的下一個記錄 while ([result next]) { //根據字段名,獲取記錄的值,存儲到字典中 NSMutableDictionary *dict = [NSMutableDictionary dictionary]; int num = [result intForColumn:@"num"]; NSString *name = [result stringForColumn:@"name"]; NSString *sex = [result stringForColumn:@"sex"]; dict[@"num"] = @(num); dict[@"name"] = name; dict[@"sex"] = sex; //把字典添加進數組中 [array addObject:dict]; } return array; }
FMDatabase
這個類是線程不安全的,若是在多個線程同時使用一個FMDatabase
實例,會形成數據混亂問題。
爲了保證線程安全,FMDB提供方便快捷的FMDatabaseQueue
類,要使用這個類,須要#import
導入頭文件"FMDatabaseQueue.h"
,FMDatabaseQueue
類的操做不少都和FMDatabase
很類似安全
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject; NSString *filePath = [path stringByAppendingPathComponent:@"FMDB.db"]; FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
[queue inDatabase:^(FMDatabase*db) { //FMDatabase數據庫操做 }];
[queue inDatabase:^(FMDatabase*db) { //插入記錄到表中 NSString *sqlStr = @"insert into mytable(num,name,sex) values(4,'xiaoming','m');"; BOOL result = [db executeUpdate:sqlStr]; if (!result) { NSLog(@"error when insert into database table"); [db close]; } }];
事務,是指做爲單個邏輯工做單元執行的一系列操做,要麼完整地執行,要麼徹底地不執行。多線程
想象一個場景,好比你要更新數據庫的大量數據,咱們須要確保全部的數據更新成功,才採起這種更新方案,若是在更新期間出現錯誤,就不能採起這種更新方案了,若是咱們不使用事務,咱們的更新操做直接對每一個記錄生效,萬一遇到更新錯誤,已經更新的數據怎麼辦?難道咱們要一個一個去找出來修改回來嗎?怎麼知道原來的數據是怎麼樣的呢?這個時候就須要使用事務實現。框架
之因此將事務放到FMDB
中去說並非由於只有FMDB
才支持事務,而是由於FMDB
將其封裝成了幾個方法來調用,不用本身寫對應的SQL而已。函數
只要在執行SQL語句前加上如下的SQL語句,就可使用事務功能了: 開啓事務的SQL語句,"begin transaction;" 進行提交的SQL語句,"commit transaction;" 進行回滾的SQL語句,"rollback transaction;"
只有事務提交了,開啓事務期間的操做纔會生效
//事務 -(void)transaction { // 開啓事務 [self.database beginTransaction]; BOOL isRollBack = NO; @try { for (int i = 0; i<500; i++) { NSNumber *num = @(i+1); NSString *name = [[NSString alloc] initWithFormat:@"student_%d",i]; NSString *sex = (i%2==0)?@"f":@"m"; NSString *sql = @"insert into mytable(num,name,sex) values(?,?,?);"; BOOL result = [database executeUpdate:sql,num,name,sex]; if ( !result ) { NSLog(@"插入失敗!"); return; } } } @catch (NSException *exception) { isRollBack = YES; // 事務回退 [self.database rollback]; } @finally { if (!isRollBack) { //事務提交 [self.database commit]; } } }
//多線程事務 - (void)transactionByQueue { //開啓事務 [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) { for (int i = 0; i<500; i++) { NSNumber *num = @(i+1); NSString *name = [[NSString alloc] initWithFormat:@"student_%d",i]; NSString *sex = (i%2==0)?@"f":@"m"; NSString *sql = @"insert into mytable(num,name,sex) values(?,?,?);"; BOOL result = [db executeUpdate:sql,num,name,sex]; if ( !result ) { //當最後*rollback的值爲YES的時候,事務回退,若是最後*rollback爲NO,事務提交 *rollback = YES; return; } } }]; }
發現一個很好的關於FMDB文檔《FMDB類的說明文檔》,裏面雖然是英文的,可是列出了全部的FMDB類的方法,很棒!下面是截圖: