Android数据库表结构自动升级

Android App开发如果涉及过数据库的朋友们肯定会碰到数据库升级的工作,Android官方的建议办法是override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)并在其中通过数据库版本比较写SQL增加表字段、创建新表等操作来达到数据库升级的功能,思路非常OK,但是项目做久了发现这块代码变超级庞大,仔细一看全是流水账代码,自己项目中曾经也是如此,时间久了代码量十分恐怖,关键的是无法通过重构减少代码量,类似如下:

db_upgrade.png

其实,之前写过一个轻量级的SQLite ORM,已经做到数据库自动创建,通过以面向对象方式进行增删改查,非常缺少自动升级这个功能。
通过查阅相关资料,得知sqlite数据库里默认会生成两个表分别是:sqlite_sequence和sqlite_master,今天看的是sqlite_master,里面存放了每张表结构(创建表的SQL):

sqlite_master.png

所以,思路就很简单了,同过检索此表可以知道新建的表是否在其中存在:

  • 不存表在则创建新表;
  • 存在表再检查所有字段是否存在,不存在则加字段(数据库升级的原则就是只增不减);

所以,写两个工具方法即可:

static boolean isTableExist(SQLiteDatabase db, String tableName) {
    Cursor cursor = null;
    try {
        cursor = db.rawQuery("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", new String[]{tableName});
        boolean hasNext = cursor.moveToNext();
        return hasNext && cursor.getInt(0) > 0;
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}

static boolean isColumnExist(SQLiteDatabase db, String tableName, String columnName) {
    Cursor cursor = null;
    try {
        cursor = db.rawQuery("SELECT count(*) FROM sqlite_master WHERE tbl_name = ? AND (sql LIKE ? OR sql LIKE ?);",
                new String[]{tableName, "%(" + columnName + "%", "%, " + columnName + " %"});
        boolean hasNext = cursor.moveToNext();
        return hasNext && cursor.getInt(0) > 0;
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}

如何运用2个方法自动升级呢:

@Override
public final void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    autoMigrate(db, mTableClasses);
}

private void autoMigrate(SQLiteDatabase db, List<Class<? extends Entity>> tableClasses) {
    for (Class<? extends Entity> clazz : tableClasses) {
        String tableName = ReflectTools.getTableName(clazz);
        boolean exist = ReflectTools.isTableExist(db, tableName);
        if (exist) {
            Field[] fields = ReflectTools.getClassFields(clazz);
            for (Field field : fields) {
                Column column = field.getAnnotation(Column.class);
                if (column == null) {
                    continue;
                }

                String columnName = !TextUtils.isEmpty(column.name()) ? column.name() : field.getName();
                String dataType = ReflectTools.getDataTypeByField(field);
                boolean columnExist = ReflectTools.isColumnExist(db, tableName, columnName);
                if (!columnExist) {
                    db.execSQL("ALTER TABLE " + tableName + " ADD " + columnName + " " + dataType);
                }
            }
        } else {
            db.execSQL(SQLBuilder.buildCreateSQL(clazz).getSql());
        }
    }
}

可能你们已经注意到这里有几个外来方法和变量,它们来自于上面所说的轻量级SQLite ORM,还有请注意onUpgrade()是加了final修饰的,意味着子类无需手动升级了。

所以,关于数据库升级,你所需要做的事情就是该创建表对象的就创建表对象,该加字段的就加字段,最后别忘记把数据库版本号升级下就好了,因为只有当Android检测出你的数据库版本好变了才会走进onUpgrade()。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容