基于FMDB的數(shù)據(jù)庫(kù)基本操作

我們都知道, 不管使用任何一種高級(jí)編程語言, 都會(huì)遇到需要做本地緩存的情況. 當(dāng)然, 本地緩存方式可能有多種方式. 但如果需要對(duì)本地緩存做靈活的操作, 基于sql 的數(shù)據(jù)庫(kù)依然是首選. 本文將從基礎(chǔ)的sql語句出發(fā), 衍申到 iOS 開發(fā)中對(duì)數(shù)據(jù)庫(kù)的應(yīng)用.

一. SQL基礎(chǔ)

SQL(結(jié)構(gòu)化查詢語言)給我們提供了數(shù)據(jù)庫(kù)的創(chuàng)表,刪表,數(shù)據(jù)的增刪改查等基本操作. 接下來將依次舉例演示這些操作.

  • 創(chuàng)表
    判斷如果不存在 StudentTable 則創(chuàng)建. 將 id 設(shè)為主鍵, 以分號(hào)結(jié)尾.
    create table if not exists StudentTable (id integer primary key, name text not null, score integer not null);
    如果主鍵不需要外界輸入, 而是通過默認(rèn)的累加方式, 可以將主鍵設(shè)為自增模式.
    create table if not exists StudentTable (id integer primary key autoincrement, name text not null, score integer not null);
    主鍵有默認(rèn)的唯一性, 如果需要將除主鍵意外的其他字段設(shè)置唯一性屬性, 需要用unique 來修飾該字段.
    create table if not exists StudentTable (id integer primary key autoincrement, name text unique not null, score integer not null);

  • 刪表
    刪除數(shù)據(jù)庫(kù)表StudentTable
    delete from StudentTable;


  • insert into StudentTable(id,name,score) values ('1','小明','99');

  • delete from StudentTable where id='1' and name='小明';

  • 修改Student表中 id = 1 的這條數(shù)據(jù), 同時(shí)修改兩個(gè)字段. 修改name = '大明', 修改score='90' . 同時(shí)修改多個(gè)字段值時(shí), 中間用逗號(hào)隔開.
    update StudentTable set name='大明',score='90' where id='1';

  • 查詢 id = 1 的這條數(shù)據(jù)的所有字段值.
    select * from StudentTable where id='1';
    查詢id = 1 的這條數(shù)據(jù)對(duì)應(yīng)的name 的字段值.
    select name from StudentTable where id = '1';
    查詢score = 90 的這條數(shù)據(jù)的name 的字段值, 并按照id 的升序排列. (如果需要降序排列, 將asc 替換成 desc 即可)
    select name from StudentTable where score = '90' order by id asc;

二. FMDB中SQL的使用

FMDB 是在iOS開發(fā)中常用的第三方數(shù)據(jù)庫(kù)操作框架, 其底層實(shí)現(xiàn)是對(duì)sqlite 的封裝. 下文中用到的self.dataBase 是FMDatabase 的單例.

1. FMDatabase 調(diào)用 sql 不需要返回?cái)?shù)據(jù)

FMDatabase 在調(diào)用sql 時(shí), 不需要返回?cái)?shù)據(jù)的情況有 增, 刪, 改. 在這種情況下, FMDatabase 提供了兩種調(diào)用方式.

  • 通過 executeUpdate直接調(diào)用組裝好的sql, 不需要傳入?yún)?shù). (以增加一條記錄為例)
  NSString *sqlString = [NSString stringWithFormat:@"insert into StudentTable(id,name,score) values ('%@','%@','%@');", @1, @"小明", @99];
       
 BOOL result = [self.dataBase executeUpdate:sqlString];
  • 通過 executeUpdateWithFormat 調(diào)用sql. FMDataBase自帶有格式化輸入占位符 '?' ;
BOOL result = [self.dataBase executeUpdateWithFormat:@"insert into StudentTable(id,name,score) values (?,?,?)", @1, @"小明", @99];

2. FMDatabase 調(diào)用 sql 語句需要返回?cái)?shù)據(jù)

FMDatabase 在調(diào)用sql 時(shí),需要返回?cái)?shù)據(jù)的操作是 查詢. 查詢操作也有以上兩種調(diào)用方式

  • 通過 executeQuery直接調(diào)用組裝好的sql, 不需要傳入?yún)?shù);
  • 通過 executeQueryWithFormat 調(diào)用sql. FMDataBase自帶有格式化輸入占位符 '?' ;

查詢操作返回?cái)?shù)據(jù)類型是FMResultSet, 需要對(duì)這個(gè)類型的數(shù)據(jù)進(jìn)行解析, 轉(zhuǎn)成模型數(shù)據(jù).

- (NSArray *)selectStudentByID:(NSNumber *)ID {
    
    NSMutableArray *resultArray = [NSMutableArray array];
    
    FMResultSet *set = [self.dataBase executeQueryWithFormat:@"select * from StudentTable where id = ?;", ID];
    while (set.next) {
        
        Student *stu = [[Student alloc] init];
        stu.ID = [set objectForColumnName:@"id"];
        stu.name = [set objectForColumnName:@"name"];
        stu.score = [set objectForColumnName:@"score"];
        [resultArray addObject:key];
    }
    return resultArray;
}

三. 異步線程的FMDB

在項(xiàng)目中曾經(jīng)遇到這么一種情況, 快速切換頁(yè)面, 大量網(wǎng)絡(luò)數(shù)據(jù)需要更新本地?cái)?shù)據(jù)庫(kù)的緩存. 操作的特點(diǎn)是: 數(shù)據(jù)量大, 對(duì)數(shù)據(jù)庫(kù)的操作頻繁, 更有甚者,多個(gè)網(wǎng)絡(luò)數(shù)據(jù)流同時(shí)操作了同一張數(shù)據(jù)表. 那么這樣的操作必然不能放到主線程中執(zhí)行, 整個(gè)app 會(huì)卡頓的無法使用, 用戶體驗(yàn)相當(dāng)不好.

這時(shí), 我考慮使用異步線程, 將這些耗時(shí)操作放到子線程中去執(zhí)行. 事實(shí)上我也這么嘗試了, app 卡頓的現(xiàn)象真的解決了. 在測(cè)試過程中, 新的問題又出現(xiàn)了. 問題就是: 多個(gè)動(dòng)作同時(shí)操作數(shù)據(jù)庫(kù)時(shí), 未必所有動(dòng)作都會(huì)被執(zhí)行. 因?yàn)槟硰垟?shù)據(jù)表正在被操作, 其他動(dòng)作則無法操作而被跳過了. 這樣, 每次從本地緩存中讀取的數(shù)據(jù)就會(huì)和預(yù)期的有較大出入.

要解決以上問題, FMDB為我們提供了基于 NSOperationQueue 的多線程操作. 將所有操作放入隊(duì)列中, iOS系統(tǒng)會(huì)自動(dòng)分配子線程, 確保每個(gè)動(dòng)作都會(huì)被執(zhí)行, 不會(huì)因?yàn)閿?shù)據(jù)庫(kù)正在被操作而丟棄其他操作.
下文中用到的self.dataBaseQueue 是FMDatabaseQueue的單例.

- (void)insertStudentsArray:(NSArray *)studentsArray {
    
    [self.dataBaseQueue inDatabase:^(FMDatabase *db) {
        for (Student *stu in studentsArray) {
            [self insertStu: stu];
        }
    }];
}

注意: FMDB提供的隊(duì)列操作是不能嵌套的, 不能隊(duì)列中再調(diào)用同一隊(duì)列. 在上面的例子中, -(void)insertStu:(Student*)stu; 這個(gè)方法內(nèi)部就不能再調(diào)用[self.dataBaseQueue inDatabase:^(FMDatabase *db) { }]; 這個(gè)方法了, 否則程序會(huì)崩潰.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容