FMDB在项目中的封装使用

作者: 倚楼听风雨wing | 来源:发表于2016-07-04 11:09 被阅读701次

    FMDB

    框架下载地址:https://github.com/ccgus/fmdb
    速度比CoreData快几十倍,realm我一直没有用,不做过多评价,现在聊一聊我在项目中是如何使用FMDB的

    单例封装###

    创建一个WYSQLiteManager继承自NSObject,里面主要用到的是FMDB中的FMDatabaseQueue

    #import <Foundation/Foundation.h>
    #import "FMDB.h"
    @class FMDatabaseQueue;
    
    @interface WYSQLiteManager : NSObject
    
    @property (nonatomic, strong) FMDatabaseQueue *queue;
    
    + (instancetype)sharedManager;
    
    @end
    

    .m中的代码:

    #import "WYSQLiteManager.h"
    // 数据库名称
    NSString *const dbName = @"nightChat.db";
    
    @implementation WYSQLiteManager
    
    + (instancetype)sharedManager {
        static id _instance;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [[WYSQLiteManager alloc] init];
        });
        return _instance;
    }
    
    - (instancetype)init {
        if (self = [super init]) {
          // 数据库在沙盒中的路径
            NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
            path = [path stringByAppendingPathComponent:dbName];
            // 使用数据库路径初始化FMDatabaseQueue
            self.queue = [[FMDatabaseQueue alloc] initWithPath:path];
            [self createTables];
        }
        return self;
    }
    
    - (void)createTables {
        NSString *path = [[NSBundle mainBundle] pathForResource:@"tables.sql" ofType:nil];
        NSError *error = nil;
        // 加载所有的建表语句
        NSString *sql = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
        if (error) {
            NSLog(@"加载数据库建表语句错误--%@", error);
        }
        
        // 创建表
        [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
            [db executeStatements:sql];
        }];
    }
    

    我的tables.sql[这里只给出了一个建表语句]

    -- fateMessage 有缘人消息列表
    CREATE TABLE IF NOT EXISTS "T_Fate_Message" (
    "messageId" INTEGER NOT NULL,   -- 消息ID
    "content" TEXT,                 -- 消息内容
    "owner_id" INTEGER,             -- 消息拥有者ID
    "sender_id" INTEGER,            -- 消息发送者ID
    "receiver_id" INTEGER,          -- 消息接受者ID
    "timestamp" LONG,               -- 消息发送时间
    "deliveryState" INTEGER,        -- 消息发送状态
    "mfrom" TEXT,                   -- 消息来源的环信用户名
    "mto" TEXT,                     -- 消息接受者的环信用户名
    "extern" TEXT,                  -- 预留字段
    "ID" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT
    );
    

    啰嗦两句,一般创建表的时候都会有一两个预留字段,因为如果使用了sqlite过后,项目发版上线了,后面要对数据库表做变动[例如增加字段],这个时候是需要做数据迁移的,这个会比较麻烦,所以一般的办法都是在建表的时候就多创建两个预留字段.并且在大多数时候存储的都是json字符串,这样的变动性会比较好,一般单独的字段大多是需要用作查询处理的.

    数据库操作##

    一般我们还会单独针对不同模块的本地化数据操作创建不同的数据访问层,例如这里创建一个WYFateMessageDAL

    /// 有缘人消息保存
    ///
    /// @param message 要保存的消息
    + (BOOL)fateMessageSave:(EMMessage *)message {
        NSString *sql = @"insert or replace into T_Fate_Message (messageId, content, owner_id, timestamp, deliveryState, mfrom, mto) values (?, ?, ?, ?, ?, ?, ?);";
        
        return [self insertFateMessage:message sql:sql];
    }
    
    /// 保存有缘人消息
    ///
    /// @param message 有缘人消息
    /// @param sql     sql语句
    ///
    /// @return 插入结果
    + (BOOL)insertFateMessage:(EMMessage *)message sql:(NSString *)sql {
        __block BOOL success = false;
        [[WYSQLiteManager sharedManager].queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
            success = [db executeUpdate:sql, message.messageId, message.contentText, GetUserID, @(message.timestamp), @(message.deliveryState), message.from, message.to];
            [self stateLog:success rollback:rollback];
        }];
        return success;
    }
    

    注意点###

    FMDatabaseQueue是一个串行队列,目的就是为了保证数据的安全性,所以我们在做数据操作的时候一定要注意多线程并发访问的数据造成的数据错乱,所以在使用的时候记住在主线程做数据库访问操作.

    相关文章

      网友评论

      • 苜蓿鬼仙:想了解一下 存储图片,尤其是多张图片如何处理?
        倚楼听风雨wing:@苜蓿鬼仙 如果图片来自服务器,那么一张图片必定对应的是一个url,如果这个时候用户点击清除缓存等操作,就会把缓存在本地磁盘上的图片删除,这个时候SDWebImage会再次根据这个url到服务器下载对应的图片
        苜蓿鬼仙:@倚楼听风雨wing 那这个原理上来讲,只是存储了图片的地址,并不是存储图片;假如存储图片地址后,图片被删除了,当再次需要从数据库中调取的时候,调的是之前的图片地址,而在对应地址上却找不到相应的图片,这样的话,不就是无法真正做到存储图片吗
        倚楼听风雨wing:@苜蓿鬼仙 如果是针对文件存储一般对于文件的内容我们都是使用SDWebImage来帮我们管理,这样下载优化也能一并处理了.如果要做存储,我们可以使用sqlite保存图片的地址,在每次需要使用的时候用SDWebImage加载就可以了.
      • 杏仁丶:感谢分享
      • Tuberose:写得很好!感谢

      本文标题:FMDB在项目中的封装使用

      本文链接:https://www.haomeiwen.com/subject/mnvcjttx.html