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

相信所有使用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")
)

推荐阅读更多精彩内容

  • 1、引言 数据库设计过程中表、字段等的命名规范也算是设计规范的一部分,不过设计规范更多的是为了确保数据库设计的合理...
    SnowflakeCloud阅读 33,832评论 0 47
  • 文/Bruce.Liu1 1.建模简介 范式:英文名称是 Normal Form,它是英国人 E.F.Codd(埃...
    BruceLiu1阅读 3,383评论 0 9
  • MySQL数据库对象与应用 2.1-MySQL数据类型 库建立好之后基本不动,和我们接触最频繁的是表. 建表就是声...
    极客圈阅读 1,322评论 0 8
  • 夜是凄惨 人们瞧着 一群受伤的人 把树插在死亡的坟墓 渴望在春天发芽 岁月是打杂的工人 学会了在痛苦中生活 他们处...
    余小胃阅读 66评论 0 2
  • 这几天都没记录,今天一并记录如下。宝宝这两天很好,生活规律吃饭香玩儿的开心。周一晚上我上自习被雨截住10点多才回家...
    薄小宝阅读 49评论 0 0