FMDB二次封裝工具類签则,讓你快速學會封裝须床,集成數(shù)據(jù)庫

上個版本為了增加用戶體驗,部分頁面集成了離線緩存數(shù)據(jù)功能渐裂,于是就在項目里使用了數(shù)據(jù)庫管理離線數(shù)據(jù)豺旬。下面交大家一步步學會使用FMDB,以及FMDB的二次封裝柒凉,同事把我二次封裝的數(shù)據(jù)庫放出來族阅,希望能夠幫助大家快速學習,集成數(shù)據(jù)庫功能吧膝捞。

一.首先看一下STDB文件結(jié)構(gòu)

STDB文件結(jié)構(gòu)
  • Table.h主要放一些Table的創(chuàng)建語句坦刀, 方便管理我的數(shù)據(jù)庫各張表創(chuàng)建
  • DBDefine.h主要放一些表名的宏定義,數(shù)據(jù)庫版本號,數(shù)據(jù)庫名字等等鲤遥,方便我們在使用數(shù)據(jù)庫過程中更直觀管理版本和各種表
  • STDBTool.h,STDBTool.m具體封裝實現(xiàn)代碼
Table.h結(jié)構(gòu)
Table.h結(jié)構(gòu)

二.具體實現(xiàn)功能

1 . STDBTool.h 頭文件看一下

STDBTool.h

我定義了三個FMDatabaseQueue 因為實際操作中我需要數(shù)據(jù)庫嵌套沐寺,如果只使用一個FMDatabaseQueue 將會陷入死循環(huán),下面看一下1FMDatabaseQueue源碼分析一下原因:
FMDatabaseQueue 全局變量
FMDatabaseQueue 全局變量
創(chuàng)建一個隊列_queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);默認是串行隊列,數(shù)據(jù)庫操作的時候FMDB源碼如下圖
FMDatabaseQueue 同步執(zhí)行源碼
FMDatabaseQueue 同步執(zhí)行源碼

同步執(zhí)行串行隊列 block塊里按著順序執(zhí)行盖奈。
demo0
demo0

任務1執(zhí)行 ——>任務二等待任務一執(zhí)行完畢執(zhí)行混坞,任務一等待任務二執(zhí)行完畢執(zhí)行,死鎖钢坦。 如果新建一個串行隊列
demo1
demo1

這樣就沒有問題究孕。 至于同步異步并行串行網(wǎng)上也有很多,不在一一介紹啦爹凹。

2 . STDBTool的初始化 厨诸,很顯然 STDBTool用的是單例啦, 看一下alloc方法

STDBTool 初始化

這里面也就是創(chuàng)建一下數(shù)據(jù)庫文件逛万,設(shè)置數(shù)據(jù)庫版本號。
當數(shù)據(jù)庫有新表需要增加時批钠,我們需要改變數(shù)據(jù)庫版本號宇植,對數(shù)據(jù)庫進行升級。

  • .查詢數(shù)據(jù)庫當前版本
NSString * sql = [NSString stringWithFormat:@"PRAGMA user_version"];
FMResultSet * rs = [db executeQuery:sql];  
    int nVersion = 0;  
    while ([rs next]) {  
        nVersion = [rs intForColumn:@"user_version"];
    } 
  • 與宏定義數(shù)據(jù)庫版本不一致 需要更新 設(shè)置 數(shù)據(jù)庫版本號
NSString *sql = [NSString stringWithFormat:@"PRAGMA user_version = %ld",(long)newVersion];  
    BOOL ret = [db executeUpdate:sql];

STDBTool初始化就這些吧埋心。也沒什么難點指郁,主要是跟大家一起回顧一下。

3 .實現(xiàn)的數(shù)據(jù)庫數(shù)據(jù)操作功能

一般數(shù)據(jù)庫操作無非是增刪改查這些基本操作拷呆,當然我的封裝也是基于實現(xiàn)這些功能的闲坎。但是根據(jù)具體情況我們需要進行封裝。

  1. 執(zhí)行單個sql語句時候茬斧,不需要使用事務處理腰懂,我們需要知道操作類型,這里我寫了個枚舉type 便于區(qū)分
-(void)executeSQL:(NSString *)sqlStr actionType:(ST_DB_ActionType)actionType withBlock:(void(^)(BOOL bRet, FMResultSet *rs, NSString *msg))block{
    [_dbQueue inDatabase:^(FMDatabase *db) {
        if (actionType == ST_DB_SELECT) {
            //查詢語句 需要返回記錄集
          FMResultSet * rs = [db executeQuery:sqlStr];
            if ([db hadError]) {
                block(NO,rs,[db lastErrorMessage]);
                NSLog(@"executeSQL error %d:  %@",[db lastErrorCode],[db lastErrorMessage]);
            }else{
                block(YES,rs,nil);
            }
        }else{
            //更新操作 只關(guān)心操作是否執(zhí)行成功项秉,不關(guān)心記錄集  返回布爾值  無執(zhí)行結(jié)果
            BOOL ret = [db executeUpdate:sqlStr];
            if ([db hadError]) {
                block(NO,nil,[db lastErrorMessage]);
                NSLog(@"executeSQL error %d:  %@",[db lastErrorCode],[db lastErrorMessage]);
            }else{
                block(ret,nil,nil);
            }
        }
    }];
}
  1. 根據(jù)查詢結(jié)果 確定是更新還是新增操作绣溜,只需要知道是否操作成功,不關(guān)心結(jié)果集 只處理一個查詢更新娄蔼,不需要事務處理
- (void)executeRelevanceSql:(NSArray *)sqlList withBlock:(void(^)(BOOL ret,NSString * errMsg))block{
    __block BOOL ret;
    [_dbQueue inDatabase:^(FMDatabase *db) {
        FMResultSet * rs = [db executeQuery:sqlList[0]];
        if ([db hadError]) {
            block(NO,[db lastErrorMessage]);
            NSLog(@"da_error_%@",[db lastErrorMessage]);
        }
        
        int nCount = 0;
        if ([rs next]) {
            //獲取查詢數(shù)據(jù)的個數(shù)
            nCount = [rs intForColumnIndex:0];
        }
        [rs close];
        
        NSString * nextSqlString = nil;
        if (nCount > 0) {
            //查詢到了結(jié)果  執(zhí)行update操作
            nextSqlString = sqlList[1];
        }else{
            //查詢無結(jié)果  執(zhí)行 insert into 操作
            nextSqlString = sqlList[2];
        }
        
        ret = [db executeUpdate:nextSqlString];
        if ([db hadError]) {
            block(NO,[db lastErrorMessage]);
            NSLog(@"da_error_%@",[db lastErrorMessage]);
        }else{
            block(ret, nil);
        }
    }];
}

注:sql語句數(shù)組怖喻,sqlList[0]查詢select語句 sqList[1] update更新語句 sqlList[2] insert into 插入語句

  1. 根據(jù)查詢結(jié)果 確定是更新還是新增操作,只需要知道是否操作成功岁诉,不關(guān)心結(jié)果集 只處理一個查詢更新锚沸,不需要事務處理
- (void)executeRelevanceSql:(NSArray *)sqlList withBlock:(void(^)(BOOL ret,NSString * errMsg))block{
    __block BOOL ret;
    [_dbQueue inDatabase:^(FMDatabase *db) {
        FMResultSet * rs = [db executeQuery:sqlList[0]];
        if ([db hadError]) {
            block(NO,[db lastErrorMessage]);
            NSLog(@"da_error_%@",[db lastErrorMessage]);
        }
        int nCount = 0;
        if ([rs next]) {
            //獲取查詢數(shù)據(jù)的個數(shù)
            nCount = [rs intForColumnIndex:0];
        }
        [rs close];
        
        NSString * nextSqlString = nil;
        if (nCount > 0) {
            //查詢到了結(jié)果  執(zhí)行update操作
            nextSqlString = sqlList[1];
        }else{
            //查詢無結(jié)果  執(zhí)行 insert into 操作
            nextSqlString = sqlList[2];
        }
        ret = [db executeUpdate:nextSqlString];
        if ([db hadError]) {
            block(NO,[db lastErrorMessage]);
            NSLog(@"da_error_%@",[db lastErrorMessage]);
        }else{
            block(ret, nil);
        }
    }];
}

注: sql語句數(shù)組,sqlList[0]查詢select語句 sqList1update更新語句 sqlList2 insert into 插入語句

4 . sqlList 是一個二維數(shù)組涕癣,每一個成員包含三個sql語句哗蜈,分別是查詢,更新,插入恬叹,并且根據(jù)查詢結(jié)果返回是執(zhí)行更新 還是 插入操作候生。使用dbQueue2 用于直接調(diào)用。批量處理绽昼,使用事務唯鸭。

- (void)executeDbQueue2RelevanceTransactionSqlList:(NSArray *)sqlList withBlock:(void(^)(BOOL bRet, NSString *msg, BOOL *bRollback))block{
    __block BOOL ret = NO;
    [_dbQueue2 inTransaction:^(FMDatabase *db, BOOL *rollback) {
        for (NSArray * singleSqlList in sqlList ) {
            FMResultSet * rs = [db executeQuery:singleSqlList[0]];
            if ([db hadError]) {
                block(NO,[db lastErrorMessage],rollback);
                NSLog(@"da_error_%@",[db lastErrorMessage]);
            }else{
                int nCount = 0;
                while ([rs next]){
                    nCount  = [rs intForColumnIndex:0];
                }
                [rs close];
                
                NSString * nextSqlString = nil;
                if (nCount > 0){
                    //執(zhí)行更新
                    nextSqlString = singleSqlList[1];
                }
                else{
                    //執(zhí)行插入
                    nextSqlString = singleSqlList[2];
                }
                
                 ret = [db executeUpdate:nextSqlString];
                if ([db hadError])
                {
                    block(NO, [db lastErrorMessage], rollback);
                    NSLog(@"executeSql Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
                }
            }
        }
         block(ret, nil, rollback);
    }];
}

注:sql語句數(shù)組,sqlArr[i][0]:查詢語句硅确;sqlArri:update語句目溉;sqlArri:insert into語句

5.sql語句數(shù)組中每個成員有2條語句,第一條是select語句菱农,第二條是insert into語句缭付,根據(jù)第一個sql的執(zhí)行結(jié)果確定第二條語句是否執(zhí)行。根據(jù)查詢結(jié)果確定是否新增循未,批量處理陷猫,使用事務處理,不需要返回記錄集使用dbQueue2的妖,用于程序中直接調(diào)用(非封裝在其他方法中)

-(void)executeInsertTransactionSqlList:(NSArray *)sqlStrList withBlock:(void(^)(BOOL bRet, NSString *msg, BOOL *bRollback))block
{
    __block BOOL ret = NO;
     NSLog(@"開始啦---");
    [_dbQueue2  inTransaction:^(FMDatabase *db, BOOL *rollback){
        
        for (NSArray *sqlArray in sqlStrList){
            FMResultSet *rs = [db executeQuery:[sqlArray objectAtIndex:0]];
            if ([db hadError]){
                block(NO, [db lastErrorMessage], rollback);
                NSLog(@"executeSql Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
            }
            
            int nCount = 0;
            while ([rs next]){
                nCount = [rs intForColumnIndex:0];
            }
            [rs close];
            
            if (nCount <= 0){
                ret = [db executeUpdate:[sqlArray objectAtIndex:1]];
                if ([db hadError])
                {
                    block(NO, [db lastErrorMessage], rollback);
                    NSLog(@"executeSql Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
                }
            }
        }
        block(ret, nil, rollback);
    }];
}

注:sql語句數(shù)組绣檬,sqlArr[i][0]:查詢語句;sqlArri:insert into語句
6.批量處理更新或者新增sql語句嫂粟,不需要返回記錄集 無事務處理

- (void)executeSQLList:(NSArray *)sqlStrList db:(FMDatabase *)db withBlock:(void(^)(BOOL bRet, NSString *msg))block{
    __block BOOL bRet = NO;
    for (NSString * sqlString in sqlStrList) {
        bRet = [db executeUpdate:sqlString];
        if ([db hadError]) {
            block(bRet,[db lastErrorMessage]);
            NSLog(@"executeSQLList Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
            break;
        }
    }
    block(bRet,nil);
}

注: sql語句數(shù)組update或者insert into語句

7.批量處理更新或者新增sql語句娇未,并且不需要返回記錄集,使用事務處理

-(void)executeTransactionSqlList:(NSArray *)sqlStrList withBlock:(void(^)(BOOL bRet, NSString *msg, BOOL *bRollback))block
{
    __block BOOL bRet = NO;
    [_dbQueue  inTransaction:^(FMDatabase *db, BOOL *rollback){
        
        for (NSString *sqlStr in sqlStrList)
        {
            bRet = [db executeUpdate:sqlStr];
            if ([db hadError])
            {
                block(bRet, [db lastErrorMessage], rollback);
                NSLog(@"executeSQLList Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
                break;
            }
        }
        block(bRet, nil, rollback);
    }];
}

注:sql語句數(shù)組update或者insert into語句

還有幾個方法在防止死循環(huán)嵌套 類似的函數(shù)星虹。
github地址可以直接下載使用零抬,感覺有用的話star一下,謝謝大家宽涌。希望能幫到大家平夜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市卸亮,隨后出現(xiàn)的幾起案子褥芒,更是在濱河造成了極大的恐慌,老刑警劉巖嫡良,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锰扶,死亡現(xiàn)場離奇詭異,居然都是意外死亡寝受,警方通過查閱死者的電腦和手機坷牛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來很澄,“玉大人京闰,你說我怎么就攤上這事颜及。” “怎么了蹂楣?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵俏站,是天一觀的道長。 經(jīng)常有香客問我痊土,道長肄扎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任赁酝,我火速辦了婚禮犯祠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酌呆。我一直安慰自己衡载,他們只是感情好,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布隙袁。 她就那樣靜靜地躺著痰娱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪菩收。 梳的紋絲不亂的頭發(fā)上梨睁,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音坛梁,去河邊找鬼而姐。 笑死腊凶,一個胖子當著我的面吹牛划咐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钧萍,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼褐缠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了风瘦?” 一聲冷哼從身側(cè)響起队魏,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎万搔,沒想到半個月后胡桨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡瞬雹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年昧谊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酗捌。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡呢诬,死狀恐怖涌哲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尚镰,我是刑警寧澤阀圾,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站狗唉,受9級特大地震影響初烘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜敞曹,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一账月、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧澳迫,春花似錦局齿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拢锹,卻和暖如春谣妻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卒稳。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工蹋半, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人充坑。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓减江,卻偏偏與公主長得像,于是被迫代替她去往敵國和親捻爷。 傳聞我的和親對象是個殘疾皇子辈灼,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

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