FMDB 使用方法

1.什么是FMDB
iOS中使用C語言函數(shù)對原生SQLite數(shù)據(jù)庫進(jìn)行增刪改查操作,復(fù)雜麻煩适篙,于是,就出現(xiàn)了一系列將SQLite API封裝的庫,如FMDB
FMDB是針對libsqlite3框架進(jìn)行封裝的三方草添,它以O(shè)C的方式封裝了SQLite的C語言的API,使用步驟與SQLite相似
FMDB的優(yōu)點(diǎn)是:
(1) 使用時(shí)面向?qū)ο蠖笾伲苊饬藦?fù)雜的C語言代碼
(2) 對比蘋果自帶的Core Data框架远寸,更加輕量級和靈活
(3) 提供多線程安全處理數(shù)據(jù)庫操作方法,保證多線程安全跟數(shù)據(jù)準(zhǔn)確性
FMDB缺點(diǎn):
(1) 因?yàn)槭荗C語言開發(fā)屠凶,只能在iOS平臺上使用驰后,所以實(shí)現(xiàn)跨平臺操作時(shí)存在限制性
FMDB 在Git上的下載鏈接地址:https://github.com/ccgus/fmdb
2.主要類型
FMDatabase:一個(gè)FMDatabase對象代表一個(gè)單獨(dú)的SQLite數(shù)據(jù)庫,通過SQLite語句執(zhí)行數(shù)據(jù)庫的增刪改查操作
FMResultSet:使用FMDatabase對象查詢數(shù)據(jù)庫后的結(jié)果集
FMDatabaseQueue:用于多線程操作數(shù)據(jù)庫矗愧,它保證線程安全
3.FMDB使用方式
(1) GItHub中下載FMDB灶芝,將文件導(dǎo)入工程中
(2) 導(dǎo)入libsqlite3.0框架,導(dǎo)入頭文件FMDatabase.h
(3) 創(chuàng)建數(shù)據(jù)庫路徑唉韭,創(chuàng)建數(shù)據(jù)庫夜涕,操作前開啟數(shù)據(jù)庫,構(gòu)建操作SQLite語句属愤,數(shù)據(jù)庫執(zhí)行增刪改查操作女器,操作完關(guān)閉數(shù)據(jù)庫
4.FMDB基本使用示例:??
(0) 創(chuàng)建Person類

@interface PersonVO : NSObject
@property (nonatomic, assign) int ID;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *phone;
@property (nonatomic, assign) int score;

@end

(1) 使用FMDBbase類創(chuàng)建數(shù)據(jù)庫

//1.創(chuàng)建database路徑
    NSString *docuPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *dbPath = [docuPath stringByAppendingPathComponent:@"test.db"];
    NSLog(@"!!!dbPath = %@",dbPath);
     //2.創(chuàng)建對應(yīng)路徑下數(shù)據(jù)庫
    db = [FMDatabase databaseWithPath:dbPath];
    //3.在數(shù)據(jù)庫中進(jìn)行增刪改查操作時(shí),需要判斷數(shù)據(jù)庫是否open住诸,如果open失敗驾胆,可能是權(quán)限或者資源不足,數(shù)據(jù)庫操作完成通常使用close關(guān)閉數(shù)據(jù)庫
    [db open];
    if (![db open]) {
        NSLog(@"db open fail");
        return;
    }
    //4.數(shù)據(jù)庫中創(chuàng)建表(可創(chuàng)建多張)
    NSString *sql = @"create table if not exists t_student ('ID' INTEGER PRIMARY KEY AUTOINCREMENT,'name' TEXT NOT NULL, 'phone' TEXT NOT NULL,'score' INTEGER NOT NULL)";
    //5.執(zhí)行更新操作 此處database直接操作贱呐,不考慮多線程問題丧诺,多線程問題,用FMDatabaseQueue 每次數(shù)據(jù)庫操作之后都會返回bool數(shù)值吼句,YES锅必,表示success,NO惕艳,表示fail,可以通過 @see lastError @see lastErrorCode @see lastErrorMessage
    BOOL result = [db executeUpdate:sql];
    if (result) {
        NSLog(@"create table success");
        
    }
    [db close];

(2) 插入命令sql語句

/**
 增刪改查中 除了查詢(executeQuery)搞隐,其余操作都用(executeUpdate)
 //1.sql語句中跟columnname 綁定的value 用 ?表示远搪,不加‘’劣纲,可選參數(shù)是對象類型如:NSString,不是基本數(shù)據(jù)結(jié)構(gòu)類型如:int谁鳍,方法自動(dòng)匹配對象類型
 - (BOOL)executeUpdate:(NSString*)sql, ...;
 //2.sql語句中跟columnname 綁定的value 用%@/%d表示癞季,不加‘’
 - (BOOL)executeUpdateWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);
 //3.sql語句中跟columnname 綁定的value 用 劫瞳?表示的地方依次用 (NSArray *)arguments 對應(yīng)的數(shù)據(jù)替代
 - (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments;
 //4.同3 ,區(qū)別在于多一個(gè)error指針绷柒,記錄更新失敗
 - (BOOL)executeUpdate:(NSString*)sql values:(NSArray * _Nullable)values error:(NSError * _Nullable __autoreleasing *)error;
 //5.同3志于,區(qū)別在于用 ? 表示的地方依次用(NSDictionary *)arguments中對應(yīng)的數(shù)據(jù)替代
 - (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments;
 - (BOOL)executeUpdate:(NSString*)sql withVAList: (va_list)args;
 */
//0.直接sql語句
//    BOOL result = [db executeUpdate:@"insert into 't_student' (ID,name,phone,score) values(110,'x1','11',83)"];
    //1.
//    BOOL result = [db executeUpdate:@"insert into 't_student'(ID,name,phone,score) values(?,?,?,?)",@111,@"x2",@"12",@23];
    //2.
//    BOOL result = [db executeUpdateWithFormat:@"insert into 't_student' (ID,name,phone,score) values(%d,%@,%@,%d)",112,@"x3",@"13",43];
    //3.
BOOL result = [db executeUpdate:@"insert into 't_student'(ID,name,phone,score) values(?,?,?,?)" withArgumentsInArray:@[@113,@"x3",@"13",@53]];
    if (result) {
        NSLog(@"insert into 't_studet' success");
        [self showAlertWithTitle:@"insert  success" message:nil person:nil];
    } else {
        [self showAlertWithTitle:[db lastError].description message:nil person:nil];
    }
    [db close];

(3) 刪除命令sql語句

[db open];
    ///0.直接sql語句
//    BOOL result = [db executeUpdate:@"delete from 't_student' where ID = 110"];
    //1.
//    BOOL result = [db executeUpdate:@"delete from 't_student' where ID = ?",@(111)];
    //2.
//    BOOL result = [db executeUpdateWithFormat:@"delete from 't_student' where ID = %d",112];
    //3.
      BOOL result = [db executeUpdate:@"delete from 't_student' where ID = ?" withArgumentsInArray:@[@113]];
    if (result) {
        NSLog(@"delete from 't_student' success");
        [self showAlertWithTitle:@"delete  success" message:nil person:nil];
    } else {
        [self showAlertWithTitle:[db lastError].description message:nil person:nil];
    }
    [db close];

(4) 更新命令sql語句

[db open];
    //0.直接sql語句
//    BOOL result = [db executeUpdate:@"update 't_student' set ID = 110 where name = 'x1'"];
    //1.
//    BOOL result = [db executeUpdate:@"update 't_student' set ID = ? where name = ?",@111,@"x2" ];
    //2.
//    BOOL result = [db executeUpdateWithFormat:@"update 't_student' set ID = %d where name = %@",113,@"x3" ];
    //3.
    BOOL result = [db executeUpdate:@"update 't_student' set ID = ? where name = ?" withArgumentsInArray:@[@113,@"x3"]];
    if (result) {
        NSLog(@"update 't_student' success");
        [self showAlertWithTitle:@"update  success" message:nil person:nil];
    } else {
        [self showAlertWithTitle:[db lastError].description message:nil person:nil];
    }
    [db close];

(5) 查詢命令sql語句

/**
FMResultSet根據(jù)column name獲取對應(yīng)數(shù)據(jù)的方法
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnIndex:
objectForColumn:
*/
[db open];
    //0.直接sql語句
//    FMResultSet *result = [db executeQuery:@"select * from 't_student' where ID = 110"];
    //1.
//    FMResultSet *result = [db executeQuery:@"select *from 't_student' where ID = ?",@111];
    //2.
//    FMResultSet *result = [db executeQueryWithFormat:@"select * from 't_student' where ID = %d",112];
    //3.
    FMResultSet *result = [db executeQuery:@"select * from 't_student' where ID = ?" withArgumentsInArray:@[@113]];
    //4
//    FMResultSet *result = [db executeQuery:@"select * from 't_sutdent' where ID = ?" withParameterDictionary:@{@"ID":@114}];
    NSMutableArray *arr = [NSMutableArray array];
    while ([result next]) {
        PersonVO *person = [PersonVO new];
        person.ID = [result intForColumn:@"ID"];
        person.name = [result stringForColumn:@"name"];
        person.phone = [result stringForColumn:@"phone"];
        person.score = [result intForColumn:@"score"];
        [arr addObject:person];
        NSLog(@"從數(shù)據(jù)庫查詢到的人員 %@",person.name);
        [self showAlertWithTitle:@"query  success" message:nil person:person];
        
    }

5.FMDB的事務(wù)
(1) 事務(wù)定義:
事務(wù)(Transaction)是并發(fā)操作的基本單位废睦,是指單個(gè)邏輯工作單位執(zhí)行的一系列操作序列伺绽,這些操作要不都成功,要不就不成功嗜湃,事務(wù)是數(shù)據(jù)庫維護(hù)數(shù)據(jù)一致性的單位奈应,在每個(gè)事務(wù)結(jié)束時(shí),都能保證數(shù)據(jù)一致性與準(zhǔn)確性购披,通常事務(wù)跟程序是兩個(gè)不同的概念杖挣,一個(gè)程序中包含多個(gè)事務(wù),事務(wù)主要解決并發(fā)條件下操作數(shù)據(jù)庫刚陡,保證數(shù)據(jù)
(2) 事務(wù)特征:
原子性(Atomic):事務(wù)中包含的一系列操作被看作一個(gè)邏輯單元惩妇,這個(gè)邏輯單元要不全部成功,要不全部失敗
一致性(Consistency):事務(wù)中包含的一系列操作筐乳,只有合法的數(shù)據(jù)被寫入數(shù)據(jù)庫屿附,一些列操作失敗之后,事務(wù)會滾到最初創(chuàng)建事務(wù)的狀態(tài)
隔離性(Isolation):對數(shù)據(jù)進(jìn)行修改的多個(gè)事務(wù)之間是隔離的哥童,每個(gè)事務(wù)是獨(dú)立的,不應(yīng)該以任何方式來影響其他事務(wù)
持久性(Durability)事務(wù)完成之后褒翰,事務(wù)處理的結(jié)果必須得到固化贮懈,它對于系統(tǒng)的影響是永久的,該修改即使出現(xiàn)系統(tǒng)固執(zhí)也將一直保留优训,真實(shí)的修改了數(shù)據(jù)庫
(3) 事務(wù)語句:

/**
 transaction:事務(wù) 開啟一個(gè)事務(wù)執(zhí)行多個(gè)任務(wù)朵你,效率高
 1.fmdb 封裝transaction 方法,操作簡單
 - (BOOL)beginTransaction;
 - (BOOL)beginDeferredTransaction;
 - (BOOL)beginImmediateTransaction;
 - (BOOL)beginExclusiveTransaction;
 - (BOOL)commit;
 - (BOOL)rollback;
 等等
 */

開啟事務(wù) :beginTransaction
回滾事務(wù):rollback
提交事務(wù):commit
(4) 事務(wù)代碼
用事務(wù)處理一系列數(shù)據(jù)庫操作揣非,省時(shí)效率高

- (void)handleTransaction:(UIButton *)sender {
    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *dbPath = [documentPath stringByAppendingPathComponent:@"test1.db"];
    FMDatabase *db = [[FMDatabase alloc]initWithPath:dbPath];
    [db open];
    if (![db isOpen]) {
        return;
    }
    BOOL result = [db executeUpdate:@"create table if not exists text1 (name text,age,integer,ID integer)"];
    if (result) {
        NSLog(@"create table success");
    }
    //1.開啟事務(wù)
    [db beginTransaction];
    NSDate *begin = [NSDate date];
    BOOL rollBack = NO;
    @try {
       //2.在事務(wù)中執(zhí)行任務(wù)
        for (int i = 0; i< 500; i++) {
            NSString *name = [NSString stringWithFormat:@"text_%d",i];
            NSInteger age = i;
            NSInteger ID = i *1000;
            
            BOOL result = [db executeUpdate:@"insert into text1(name,age,ID) values(:name,:age,:ID)" withParameterDictionary:@{@"name":name,@"age":[NSNumber numberWithInteger:age],@"ID":@(ID)}];
            if (result) {
                NSLog(@"在事務(wù)中insert success");
            }
        }
    }
    @catch(NSException *exception) {
        //3.在事務(wù)中執(zhí)行任務(wù)失敗抡医,退回開啟事務(wù)之前的狀態(tài)
        rollBack = YES;
        [db rollback];
    }
    @finally {
        //4. 在事務(wù)中執(zhí)行任務(wù)成功之后
        rollBack = NO;
        [db commit];
    }
    NSDate *end = [NSDate date];
    NSTimeInterval time = [end timeIntervalSinceDate:begin];
    NSLog(@"在事務(wù)中執(zhí)行插入任務(wù) 所需要的時(shí)間 = %f",time);
    
}

未使用事務(wù)執(zhí)行一系列操作

-(void)handleNotransaction:(UIButton *)sender {
    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *dbPath = [documentPath stringByAppendingPathComponent:@"test1.db"];
    FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
    [db open];
    if (![db isOpen]) {
        return;
    }
    BOOL result = [db executeUpdate:@"create table if not exists text2('ID' INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,age INTRGER)"];
    if (!result) {
        [db close];
    }
    NSDate *begin = [NSDate date];
    for (int i = 0; i< 500; i++) {
        NSString *name = [NSString stringWithFormat:@"text_%d",i];
        NSInteger age = i;
        NSInteger ID = i *1000;
        
        BOOL result = [db executeUpdate:@"insert into text2(name,age,ID) values(:name,:age,:ID)" withParameterDictionary:@{@"name":name,@"age":[NSNumber numberWithInteger:age],@"ID":@(ID)}];
        if (result) {
            NSLog(@"不在事務(wù)中insert success");
        }
    }
    NSDate *end = [NSDate date];
    NSTimeInterval time = [end timeIntervalSinceDate:begin];
    NSLog(@"不在事務(wù)中執(zhí)行插入任務(wù) 所需要的時(shí)間 = %f",time);
}

比較結(jié)果如下:
在事務(wù)中執(zhí)行插入任務(wù) 所需要的時(shí)間 = 0.426221
不在事務(wù)中執(zhí)行插入任務(wù) 所需要的時(shí)間 = 0.790417

  1. 附練習(xí)demo:https://github.com/sisios/fmdb_demo
    Realm使用方法:http://www.reibang.com/p/73b1f509a41f
    note: 由于本人水平有限,文中出現(xiàn)錯(cuò)誤或者不足之處在所難免早敬,敬請各位高人批評指正忌傻。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市搞监,隨后出現(xiàn)的幾起案子水孩,更是在濱河造成了極大的恐慌,老刑警劉巖琐驴,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俘种,死亡現(xiàn)場離奇詭異秤标,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)宙刘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門苍姜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人悬包,你說我怎么就攤上這事衙猪。” “怎么了玉罐?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵屈嗤,是天一觀的道長。 經(jīng)常有香客問我吊输,道長饶号,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任季蚂,我火速辦了婚禮茫船,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扭屁。我一直安慰自己算谈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布料滥。 她就那樣靜靜地躺著然眼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪葵腹。 梳的紋絲不亂的頭發(fā)上高每,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機(jī)與錄音践宴,去河邊找鬼鲸匿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛阻肩,可吹牛的內(nèi)容都是我干的带欢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼烤惊,長吁一口氣:“原來是場噩夢啊……” “哼乔煞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柒室,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤瘤缩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后伦泥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剥啤,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锦溪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了府怯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刻诊。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖牺丙,靈堂內(nèi)的尸體忽然破棺而出则涯,到底是詐尸還是另有隱情,我是刑警寧澤冲簿,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布粟判,位于F島的核電站,受9級特大地震影響峦剔,放射性物質(zhì)發(fā)生泄漏档礁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一吝沫、第九天 我趴在偏房一處隱蔽的房頂上張望呻澜。 院中可真熱鬧,春花似錦惨险、人聲如沸羹幸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栅受。三九已至,卻和暖如春恭朗,著一層夾襖步出監(jiān)牢的瞬間窘疮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工冀墨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涛贯。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓诽嘉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親弟翘。 傳聞我的和親對象是個(gè)殘疾皇子虫腋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容