美文网首页iOS Developer
避免sqlite数据库升级痛苦的小技巧

避免sqlite数据库升级痛苦的小技巧

作者: KevinTing | 来源:发表于2016-12-28 22:07 被阅读208次

    相信所有使用sqlite做本地缓存的人,开发中不可避免的一件事情就是数据库版本迁移升级,这真的是一件很蛋疼的事情。蛋疼在哪里?
    1、升级的逻辑,iOS里面你得自己写逻辑,比如记录数据库版本,然后比对啥的。有个基于FMDB 的FMDBMigrationManager,不过用起来也不是很顺手。在Android开发中,至少系统SDK还提供了相关的升级API。
    2、当需要做迁移的时候,也有很多坑,比如说模型:

    @interface User : NSObject
    
    @property (nonatomic, assign) long long userId;
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) NSUInteger *age;
    
    @end
    
    // sql建表语句
    CREATE TABLE "User" (
         "userId" INTEGER NOT NULL,
         "name" TEXT,
         "age" INTEGER,
        PRIMARY KEY("userId")
    )
    

    对应这个模型,数据库里面已经有一张User表了,后面要往User里面增加属性hobby,那么对数据库中已经存在的User表要做如下修改:

    ALTER TABLE User ADD COLUMN hobby;
    

    但是遇到删除属性或者改名字啥的,那就比较蛋疼了,并没有相关的sql语句。你能做的是把数据全读出来,然后建一个新的User表,然后再写进去。

    如何避免,或者最小化这种痛苦呢?一是在建表的时候把所有情况都考虑进去,后面不再改动model的表结构,这显然不太现实,老版总有改需求的时候。第二种是使用模糊建表方法:所谓模糊建表就是说创建模型表的时候,将数据揉成一坨丢进去,取出来的时候再解析。建表的时候,只取下面几个属性:
    1、主键,比如上面的userId。
    2、排序属性,比如上面User要按照年龄排序的话,最好把age属性也存下来。
    3、数据,所有的内容打包成一个jsonData属性,存起来。
    那么建表的语句是这样的:

    // sql建表语句
    CREATE TABLE "User" (
         "userId" INTEGER NOT NULL,
         "age" INTEGER,
         "jsonData" TEXT,
        PRIMARY KEY("userId")
    )
    

    jsonData从哪里来?很简单,用YYModel之类的模型框架转一遍就够了,下面是代码:

    // 存数据
    [self.cacheDatabaseQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
            NSString *sql = @"INSERT OR REPLACE INTO User (userId, age, jsonData) VALUES (?, ?, ?);";
            NSNumber *numUserId = [NSNumber numberWithLongLong:user.userId];
            NSNumber *numAge = [NSNumber numberWithUnsignedInteger:user.age];
            NSString *jsonData = [user yy_modelToJSONString];
            success = [db executeUpdate:sql withArgumentsInArray:@[numUserId, numAge, jsonData]];
            if (!success) {
                *rollback = YES;
            }
        }];
    
    // 取数据
        NSMutableArray *array = [NSMutableArray array];
        [self.cacheDatabaseQueue inDatabase:^(FMDatabase *db) {
            NSString *sql = @"SELECT * FROM User ORDER BY age DESC";
            FMResultSet *rsl = [db executeQuery:sql];
            while ([rsl next]) {
                NSString *jsonData = [rsl stringForColumn:@"jsonData"];
                [array addObject:[User yy_modelWithJSON:jsonData]];
            }
            [rsl close];
        }];
    

    这样做的坏处在于,userId和age两个数据在jsonData里面也有一份,有冗余。当然也可以在使用YYModel框架提供的方法在序列化jsonData的时候过滤掉userId和age属性,但是一般没必要这样做,因为冗余数据量很小。好处在于:
    1、数据库升级迁移的时候,增加一个属性,或者减少一个属性,你只用改模型就好了,存数据和取数据的代码依然可以用。排序属性和主键属性一般没人会改吧?如果你的老板要你改这种基本的属性的话,那么请打死他!
    2、用YYModel等模型框架来序列化和反序列化减少了存取数据大量繁琐的代码。
    3、之所以存取主键和排序属性在于这是必须的,主键用来区分,排序属性用来排序,其他的属性统统归为非重要属性,丢到那一坨jsonData里面就可以了。在写创建表的sql语句时,也简化了好多,你只用写很短的几行就行了。当属性比较多的时候,再也不用像这样写了,又臭又长,又容易出错:

    CREATE TABLE "User" (
         "userId" INTEGER NOT NULL,
         "name" TEXT,
         "age" INTEGER,
         "sex" TEXT,
         "languageScores" integer,
         "mathScores" integer,
         "historyScores" integer,
         "class" TEXT,
         "grade" TEXT,
        PRIMARY KEY("userId")
    )
    

    相关文章

      网友评论

        本文标题:避免sqlite数据库升级痛苦的小技巧

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