1. 程式人生 > >iOS FMDB資料庫框架使用 —— HERO部落格

iOS FMDB資料庫框架使用 —— HERO部落格

FMDB簡介:

是iOS平臺的第三方資料庫框架,將SQLite API以OC的方式進行封裝,面向物件,使用便捷。


主要的類:

FMDatabase:一個FMDatabase物件就代表一個單獨的SQLite資料庫,用來執行SQL語句,進行增刪查改操作。

FMResultSet:使用FMDatabase執行查詢後的結果集。

FMDatabaseQueue:保證執行緒安全,可以在多執行緒中同時讀寫、執行多個查詢或更新。

使用:

建立佇列物件:

NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"HWDownloadVideoCaches.sqlite"];

// 建立佇列物件,內部會自動建立一個數據庫, 並且自動開啟
_dbQueue = [FMDatabaseQueue databaseQueueWithPath:path];

創表:下面代表建立一張名為t_videoCaches的資料表,包含3個欄位,預設且自增的主鍵id欄位、totalFileSize欄位、url欄位。如“url text”代表欄位名字是url,型別是text,其中除主鍵外,型別可以不寫,為了方便閱讀及程式設計規範還是建議寫上。

[_dbQueue inDatabase:^(FMDatabase *db) {
    // 創表
    BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_videoCaches (id integer PRIMARY KEY AUTOINCREMENT, totalFileSize integer, url text)"];
    if (result) {
        NSLog(@"建立成功");
    }else {
        NSLog(@"建立失敗");
    }
}];

常用型別:

整數資料型別:integer、bigint、smallint、tinyint

浮點資料型別:float、double、real

字元型資料型別:char(n)、varchar(n)、text

二進位制資料:blob

日期型別:date、time、datetime、timestamp

增加資料:這裡有一點要注意,不要直接傳入基礎型別,如int,要封裝成物件,不然會crash掉

[_dbQueue inDatabase:^(FMDatabase *db) {
    BOOL result = [db executeUpdate:@"INSERT INTO t_videoCaches (totalFileSize, url) VALUES (?, ?)", [NSNumber numberWithInteger:1000], @"https://blog.csdn.net/hero_wqb"];
    if (result) {
        NSLog(@"插入成功");
    }else {
        NSLog(@"插入失敗");
    }
}];

刪除資料:下面代表通過url在t_videoCaches表中查詢資料,並將其刪除。

[_dbQueue inDatabase:^(FMDatabase *db) {
    BOOL result = [db executeUpdate:@"DELETE FROM t_videoCaches WHERE url = ?", url];
    if (result) {
        NSLog(@"刪除成功");
    }else {
        NSLog(@"刪除失敗");
    }
}];

查詢資料:

1)快速查詢某一資料:下面代表在t_videoCaches表中,根據url查詢資料對應的totalFileSize。對應有stringForColumn:、boolForColumn:、doubleForColumn:、dataForColumn:、objectForColumn:等方法

NSInteger totalFileSize = [db intForQuery:@"SELECT totalFileSize FROM t_videoCaches WHERE url = ?", url];

2)根據查詢條件,返回一個集合:下面代表查詢所有資料。

[_dbQueue inDatabase:^(FMDatabase *db) {
    FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM t_videoCaches"];
    while ([resultSet next]) {
        NSInteger totalFileSize = [resultSet intForColumn:@"totalFileSize"];
        NSString *url = [resultSet stringForColumn:@"url"];
        NSLog(@"totalFileSize:%ld, url:%@", totalFileSize, url);
    }
}];

修改資料:

[_dbQueue inDatabase:^(FMDatabase *db) {
    BOOL result = [db executeUpdate:@"UPDATE t_videoCaches SET totalFileSize = ? WHERE url = ?", [NSNumber numberWithInteger:2000], @"https://blog.csdn.net/hero_wqb"];
    if (result) {
        NSLog(@"修改成功");
    }else {
        NSLog(@"修改失敗");
    }
}];

一些常用的sql語句:

表:(其中table為自定義表名稱,若表已存在不會重複建立)

"CREATE TABLE IF NOT EXISTS table (id integer PRIMARY KEY AUTOINCREMENT, variableA integer, variableB text)"

插入資料:(?指代變數,需要我們傳入)

"INSERT INTO table (variableA, variableB) VALUES (?, ?)"

刪除資料:(通過變數A查找出資料並刪除)

"DELETE FROM table WHERE variableA = ?"

查詢資料:

通過變數A查尋變數B的值:

"SELECT variableB FROM table WHERE variableA = ?"

查詢整張表全部資料:(根據主鍵自增的順序返回)

"SELECT * FROM table"

通過變數A查詢資料:(根據主鍵自增的順序返回)

"SELECT * FROM table WHERE variableA = ?"

查詢變數A不滿足某條件的資料:(根據主鍵自增的順序返回)

 "SELECT * FROM table WHERE variableA != ?"

通過變數A查詢資料:(根據變數B由大到小的順序返回,desc:倒序,asc:正序)

"SELECT * FROM table WHERE variableA = ? order by variableB desc"

通過變數A查詢資料:(根據變數B由小到大的順序返回第一條,limit 0,1:從第0個座標開始,取1條資料)

"SELECT * FROM table WHERE variableA = ? order by variableB asc limit 0,1"

修改資料:(通過變數A查詢資料,修改其變數B的值)

"UPDATE table SET variableB = ? WHERE variableA = ?"

封裝了一個單例,下面貼上程式碼:

.h檔案:
#import <Foundation/Foundation.h>

typedef NS_OPTIONS(NSUInteger, HWDBUpdateOption) {
    HWDBUpdateOptionState         = 1 << 0,  // 更新狀態
    HWDBUpdateOptionLastStateTime = 1 << 1,  // 更新狀態最後改變的時間
    HWDBUpdateOptionResumeData    = 1 << 2,  // 更新下載的資料
    HWDBUpdateOptionProgressData  = 1 << 3,  // 更新進度資料
    HWDBUpdateOptionAllParam      = 1 << 4   // 更新全部資料
};

@interface HWDataBaseManager : NSObject

// 獲取單例
+ (instancetype)shareManager;

// 插入資料
- (void)insertModel:(HWDownloadModel *)model;

// 獲取資料
- (HWDownloadModel *)getModelWithUrl:(NSString *)url;    // 根據url獲取資料
- (HWDownloadModel *)getWaitingModel;                    // 獲取第一條等待的資料
- (HWDownloadModel *)getLastDownloadingModel;            // 獲取最後一條正在下載的資料
- (NSArray<HWDownloadModel *> *)getAllCacheData;         // 獲取所有資料
- (NSArray<HWDownloadModel *> *)getAllDownloadingData;   // 根據lastStateTime倒敘獲取所有正在下載的資料
- (NSArray<HWDownloadModel *> *)getAllDownloadedData;    // 獲取所有下載完成的資料
- (NSArray<HWDownloadModel *> *)getAllUnDownloadedData;  // 獲取所有未下載完成的資料(包含正在下載、等待、暫停、錯誤)
- (NSArray<HWDownloadModel *> *)getAllWaitingData;       // 獲取所有等待下載的資料

// 更新資料
- (void)updateWithModel:(HWDownloadModel *)model option:(HWDBUpdateOption)option;

// 刪除資料
- (void)deleteModelWithUrl:(NSString *)url;

@end

.m檔案:

#import "HWDataBaseManager.h"

typedef NS_ENUM(NSInteger, HWDBGetDateOption) {
    HWDBGetDateOptionAllCacheData = 0,      // 所有快取資料
    HWDBGetDateOptionAllDownloadingData,    // 所有正在下載的資料
    HWDBGetDateOptionAllDownloadedData,     // 所有下載完成的資料
    HWDBGetDateOptionAllUnDownloadedData,   // 所有未下載完成的資料
    HWDBGetDateOptionAllWaitingData,        // 所有等待下載的資料
    HWDBGetDateOptionModelWithUrl,          // 通過url獲取單條資料
    HWDBGetDateOptionWaitingModel,          // 第一條等待的資料
    HWDBGetDateOptionLastDownloadingModel,  // 最後一條正在下載的資料
};

@interface HWDataBaseManager ()

@property (nonatomic, strong) FMDatabaseQueue *dbQueue;

@end

@implementation HWDataBaseManager

+ (instancetype)shareManager
{
    static HWDataBaseManager *manager = nil;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc] init];
    });
    
    return manager;
}

- (instancetype)init
{
    if (self = [super init]) {
        [self creatVideoCachesTable];
    }
    
    return self;
}

// 創表
- (void)creatVideoCachesTable
{
    // 資料庫檔案路徑
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"HWDownloadVideoCaches.sqlite"];
    
    // 建立佇列物件,內部會自動建立一個數據庫, 並且自動開啟
    _dbQueue = [FMDatabaseQueue databaseQueueWithPath:path];

    [_dbQueue inDatabase:^(FMDatabase *db) {
        // 創表
        BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_videoCaches (id integer PRIMARY KEY AUTOINCREMENT, vid text, fileName text, url text, resumeData blob, totalFileSize integer, tmpFileSize integer, state integer, progress float, lastSpeedTime integer, intervalFileSize integer, lastStateTime integer)"];
        if (result) {
//            HWLog(@"視訊快取資料表建立成功");
        }else {
            HWLog(@"視訊快取資料表建立失敗");
        }
    }];
}

// 插入資料
- (void)insertModel:(HWDownloadModel *)model
{
    [_dbQueue inDatabase:^(FMDatabase *db) {
        BOOL result = [db executeUpdate:@"INSERT INTO t_videoCaches (vid, fileName, url, resumeData, totalFileSize, tmpFileSize, state, progress, lastSpeedTime, intervalFileSize, lastStateTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", model.vid, model.fileName, model.url, model.resumeData, [NSNumber numberWithInteger:model.totalFileSize], [NSNumber numberWithInteger:model.tmpFileSize], [NSNumber numberWithInteger:model.state], [NSNumber numberWithFloat:model.progress], [NSNumber numberWithInteger:0], [NSNumber numberWithInteger:0], [NSNumber numberWithInteger:0]];
        if (result) {
//            HWLog(@"插入成功:%@", model.fileName);
        }else {
            HWLog(@"插入失敗:%@", model.fileName);
        }
    }];
}

// 獲取單條資料
- (HWDownloadModel *)getModelWithUrl:(NSString *)url
{
    return [self getModelWithOption:HWDBGetDateOptionModelWithUrl url:url];
}

// 獲取第一條等待的資料
- (HWDownloadModel *)getWaitingModel
{
    return [self getModelWithOption:HWDBGetDateOptionWaitingModel url:nil];
}

// 獲取最後一條正在下載的資料
- (HWDownloadModel *)getLastDownloadingModel
{
    return [self getModelWithOption:HWDBGetDateOptionLastDownloadingModel url:nil];
}

// 獲取所有資料
- (NSArray<HWDownloadModel *> *)getAllCacheData
{
    return [self getDateWithOption:HWDBGetDateOptionAllCacheData];
}

// 根據lastStateTime倒敘獲取所有正在下載的資料
- (NSArray<HWDownloadModel *> *)getAllDownloadingData
{
    return [self getDateWithOption:HWDBGetDateOptionAllDownloadingData];
}

// 獲取所有下載完成的資料
- (NSArray<HWDownloadModel *> *)getAllDownloadedData
{
    return [self getDateWithOption:HWDBGetDateOptionAllDownloadedData];
}

// 獲取所有未下載完成的資料
- (NSArray<HWDownloadModel *> *)getAllUnDownloadedData
{
    return [self getDateWithOption:HWDBGetDateOptionAllUnDownloadedData];
}

// 獲取所有等待下載的資料
- (NSArray<HWDownloadModel *> *)getAllWaitingData
{
   return [self getDateWithOption:HWDBGetDateOptionAllWaitingData];
}

// 獲取單條資料
- (HWDownloadModel *)getModelWithOption:(HWDBGetDateOption)option url:(NSString *)url
{
    __block HWDownloadModel *model = nil;
    
    [_dbQueue inDatabase:^(FMDatabase *db) {
        FMResultSet *resultSet;
        switch (option) {
            case HWDBGetDateOptionModelWithUrl:
                resultSet = [db executeQuery:@"SELECT * FROM t_videoCaches WHERE url = ?", url];
                break;
                
            case HWDBGetDateOptionWaitingModel:
                resultSet = [db executeQuery:@"SELECT * FROM t_videoCaches WHERE state = ? order by lastStateTime asc limit 0,1", [NSNumber numberWithInteger:HWDownloadStateWaiting]];
                break;
                
            case HWDBGetDateOptionLastDownloadingModel:
                resultSet = [db executeQuery:@"SELECT * FROM t_videoCaches WHERE state = ? order by lastStateTime desc limit 0,1", [NSNumber numberWithInteger:HWDownloadStateDownloading]];
                break;
                
            default:
                break;
        }
        
        while ([resultSet next]) {
            model = [[HWDownloadModel alloc] initWithFMResultSet:resultSet];
        }
    }];
    
    return model;
}

// 獲取資料集合
- (NSArray<HWDownloadModel *> *)getDateWithOption:(HWDBGetDateOption)option
{
    __block NSArray<HWDownloadModel *> *array = nil;
    
    [_dbQueue inDatabase:^(FMDatabase *db) {
        FMResultSet *resultSet;
        switch (option) {
            case HWDBGetDateOptionAllCacheData:
                resultSet = [db executeQuery:@"SELECT * FROM t_videoCaches"];
                break;
                
            case HWDBGetDateOptionAllDownloadingData:
                resultSet = [db executeQuery:@"SELECT * FROM t_videoCaches WHERE state = ? order by lastStateTime desc", [NSNumber numberWithInteger:HWDownloadStateDownloading]];
                break;
                
            case HWDBGetDateOptionAllDownloadedData:
                resultSet = [db executeQuery:@"SELECT * FROM t_videoCaches WHERE state = ?", [NSNumber numberWithInteger:HWDownloadStateFinish]];
                break;
                
            case HWDBGetDateOptionAllUnDownloadedData:
                resultSet = [db executeQuery:@"SELECT * FROM t_videoCaches WHERE state != ?", [NSNumber numberWithInteger:HWDownloadStateFinish]];
                break;
                
            case HWDBGetDateOptionAllWaitingData:
                resultSet = [db executeQuery:@"SELECT * FROM t_videoCaches WHERE state = ?", [NSNumber numberWithInteger:HWDownloadStateWaiting]];
                break;
                
            default:
                break;
        }
        
        NSMutableArray *tmpArr = [NSMutableArray array];
        while ([resultSet next]) {
            [tmpArr addObject:[[HWDownloadModel alloc] initWithFMResultSet:resultSet]];
        }
        array = tmpArr;
    }];
    
    return array;
}

// 更新資料
- (void)updateWithModel:(HWDownloadModel *)model option:(HWDBUpdateOption)option
{
    [_dbQueue inDatabase:^(FMDatabase *db) {
        if (option & HWDBUpdateOptionState) {
            [self postStateChangeNotificationWithFMDatabase:db model:model];
            [db executeUpdate:@"UPDATE t_videoCaches SET state = ? WHERE url = ?", [NSNumber numberWithInteger:model.state], model.url];
        }
        if (option & HWDBUpdateOptionLastStateTime) {
            [db executeUpdate:@"UPDATE t_videoCaches SET lastStateTime = ? WHERE url = ?", [NSNumber numberWithInteger:[HWToolBox getTimeStampWithDate:[NSDate date]]], model.url];
        }
        if (option & HWDBUpdateOptionResumeData) {
            [db executeUpdate:@"UPDATE t_videoCaches SET resumeData = ? WHERE url = ?", model.resumeData, model.url];
        }
        if (option & HWDBUpdateOptionProgressData) {
            [db executeUpdate:@"UPDATE t_videoCaches SET tmpFileSize = ?, totalFileSize = ?, progress = ?, lastSpeedTime = ?, intervalFileSize = ? WHERE url = ?", [NSNumber numberWithInteger:model.tmpFileSize], [NSNumber numberWithFloat:model.totalFileSize], [NSNumber numberWithFloat:model.progress], [NSNumber numberWithInteger:model.lastSpeedTime], [NSNumber numberWithInteger:model.intervalFileSize], model.url];
        }
        if (option & HWDBUpdateOptionAllParam) {
            [self postStateChangeNotificationWithFMDatabase:db model:model];
            [db executeUpdate:@"UPDATE t_videoCaches SET resumeData = ?, totalFileSize = ?, tmpFileSize = ?, progress = ?, state = ?, lastSpeedTime = ?, intervalFileSize = ?, lastStateTime = ? WHERE url = ?", model.resumeData, [NSNumber numberWithInteger:model.totalFileSize], [NSNumber numberWithInteger:model.tmpFileSize], [NSNumber numberWithFloat:model.progress], [NSNumber numberWithInteger:model.state], [NSNumber numberWithInteger:model.lastSpeedTime], [NSNumber numberWithInteger:model.intervalFileSize], [NSNumber numberWithInteger:[HWToolBox getTimeStampWithDate:[NSDate date]]], model.url];
        }
    }];
}

// 狀態變更通知
- (void)postStateChangeNotificationWithFMDatabase:(FMDatabase *)db model:(HWDownloadModel *)model
{
    // 原狀態
    NSInteger oldState = [db intForQuery:@"SELECT state FROM t_videoCaches WHERE url = ?", model.url];
    if (oldState != model.state) {
        // 狀態變更通知
        [[NSNotificationCenter defaultCenter] postNotificationName:HWDownloadStateChangeNotification object:model];
    }
}

// 刪除資料
- (void)deleteModelWithUrl:(NSString *)url
{
    [_dbQueue inDatabase:^(FMDatabase *db) {
        BOOL result = [db executeUpdate:@"DELETE FROM t_videoCaches WHERE url = ?", url];
        if (result) {
//            HWLog(@"刪除成功:%@", url);
        }else {
            HWLog(@"刪除失敗:%@", url);
        }
    }];
}

@end

寫部落格的初心是希望大家共同交流成長,博主水平有限難免有偏頗之處,歡迎批評指正。