Android數(shù)據(jù)庫表結(jié)構(gòu)自動升級

Android App開發(fā)如果涉及過數(shù)據(jù)庫的朋友們肯定會碰到數(shù)據(jù)庫升級的工作,Android官方的建議辦法是override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)并在其中通過數(shù)據(jù)庫版本比較寫SQL增加表字段就轧、創(chuàng)建新表等操作來達到數(shù)據(jù)庫升級的功能馁龟,思路非常OK是尔,但是項目做久了發(fā)現(xiàn)這塊代碼變超級龐大幻枉,仔細一看全是流水賬代碼牲芋,自己項目中曾經(jīng)也是如此呜达,時間久了代碼量十分恐怖,關(guān)鍵的是無法通過重構(gòu)減少代碼量滑潘,類似如下:

db_upgrade.png

其實垢乙,之前寫過一個輕量級的SQLite ORM,已經(jīng)做到數(shù)據(jù)庫自動創(chuàng)建语卤,通過以面向?qū)ο蠓绞竭M行增刪改查追逮,非常缺少自動升級這個功能。
通過查閱相關(guān)資料粹舵,得知sqlite數(shù)據(jù)庫里默認會生成兩個表分別是:sqlite_sequence和sqlite_master钮孵,今天看的是sqlite_master,里面存放了每張表結(jié)構(gòu)(創(chuàng)建表的SQL):

sqlite_master.png

所以眼滤,思路就很簡單了巴席,同過檢索此表可以知道新建的表是否在其中存在:

  • 不存表在則創(chuàng)建新表;
  • 存在表再檢查所有字段是否存在诅需,不存在則加字段(數(shù)據(jù)庫升級的原則就是只增不減)漾唉;

所以,寫兩個工具方法即可:

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());
        }
    }
}

可能你們已經(jīng)注意到這里有幾個外來方法和變量诱担,它們來自于上面所說的輕量級SQLite ORM毡证,還有請注意onUpgrade()是加了final修飾的电爹,意味著子類無需手動升級了蔫仙。

所以,關(guān)于數(shù)據(jù)庫升級丐箩,你所需要做的事情就是該創(chuàng)建表對象的就創(chuàng)建表對象摇邦,該加字段的就加字段,最后別忘記把數(shù)據(jù)庫版本號升級下就好了屎勘,因為只有當(dāng)Android檢測出你的數(shù)據(jù)庫版本好變了才會走進onUpgrade()施籍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市概漱,隨后出現(xiàn)的幾起案子丑慎,更是在濱河造成了極大的恐慌,老刑警劉巖瓤摧,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竿裂,死亡現(xiàn)場離奇詭異,居然都是意外死亡照弥,警方通過查閱死者的電腦和手機腻异,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來这揣,“玉大人悔常,你說我怎么就攤上這事影斑。” “怎么了机打?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵矫户,是天一觀的道長。 經(jīng)常有香客問我残邀,道長吏垮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任罐旗,我火速辦了婚禮膳汪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘九秀。我一直安慰自己遗嗽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布鼓蜒。 她就那樣靜靜地躺著痹换,像睡著了一般。 火紅的嫁衣襯著肌膚如雪都弹。 梳的紋絲不亂的頭發(fā)上娇豫,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天,我揣著相機與錄音畅厢,去河邊找鬼冯痢。 笑死,一個胖子當(dāng)著我的面吹牛框杜,可吹牛的內(nèi)容都是我干的浦楣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼咪辱,長吁一口氣:“原來是場噩夢啊……” “哼振劳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起油狂,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤历恐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后专筷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弱贼,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年仁堪,在試婚紗的時候發(fā)現(xiàn)自己被綠了哮洽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡弦聂,死狀恐怖鸟辅,靈堂內(nèi)的尸體忽然破棺而出氛什,到底是詐尸還是另有隱情,我是刑警寧澤匪凉,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布枪眉,位于F島的核電站,受9級特大地震影響再层,放射性物質(zhì)發(fā)生泄漏贸铜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一聂受、第九天 我趴在偏房一處隱蔽的房頂上張望蒿秦。 院中可真熱鬧,春花似錦蛋济、人聲如沸棍鳖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渡处。三九已至,卻和暖如春祟辟,著一層夾襖步出監(jiān)牢的瞬間医瘫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工旧困, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留醇份,地道東北人。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓叮喳,卻偏偏與公主長得像被芳,于是被迫代替她去往敵國和親缰贝。 傳聞我的和親對象是個殘疾皇子馍悟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容