greenDAO自動化升級探索

greenDAO自動化升級探索

2018.01.09 13:20:09字數 989閱讀 967

前言

好像有好久沒寫博客的樣子~ 行,那今天就再找個理由吹一波。 前段時間研究了一下greendao數據庫升級模塊,發現了一些存在的一些問題痛點,特拿來晾曬一下,以防發黴。

 

問題現狀

話說爲什麼要做數據庫自動升級這塊的探索呢,主要有以下幾點原因:

  • 現有的數據庫升級方式過於繁瑣,每個版本都需要進行一次手動升級,每次升級都要寫一大推if else判斷新舊數據庫版本,一不小心就容易出錯。
  • 出現跨版本升級數據庫的時候,偶爾會出現數據庫字段丟失的情況,造成一些用戶閃退現象。
  • 主要還是人懶,不想每次都寫一大堆重複的代碼

思考

話說有沒有一種方式能夠比較優雅地解決這個問題呢?一波搜索後,發現很多解決方案基本都是類似的,分爲兩類:

第一類:根據當前版本依次遞歸的常規升級方式,即每個新版發佈都在對應的版本號下面加入新增的表或者字段。這種傳統的升級方式,顯得不夠“自動化”,寫起來比較麻煩,而且有時候還容易遺漏掉部分新增字段,造成應用的崩潰問題。
第二類:基本上參考了stackoverflow上面一位大佬的自動化升級方式。他的思路是這樣的:
1.拷貝原有數據表,新建temp表備份數據
2.刪除原有數據表
3.新建現有數據表
4.把temp表備份數據插入到新建的現有表中
5.刪除備份temp表
6.balabalabla...

 

反正就是一頓操作猛如虎,數據搬過來搬過去,刪完再建、各種反射,看起來很炫酷的樣子。
我就在想,爲什麼就不直接遍歷檢測 缺失表 + 缺失表字段,然後直接插入缺失的表或字段呢?如果可以這樣操作的話,那麼性能方面肯定會有一個顯著的提升,極大的減少了數據庫操作開銷,豈不是看起來很棒棒?

 
窩草,這圖怎麼這麼大

解決方案

這個時候,一個熱乎的方案新鮮出爐了。主要思路還是遍歷數據庫尋找缺失的表和表字段。然後完善對應的表結構。

public final class MigrationHelper {

    private static final String TAG = "MigrationHelper";
    private static final String SQLITE_MASTER = "sqlite_master";
    private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master";

    public static void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        Database database = new StandardDatabase(db);
        migrate(database, daoClasses);
    }


    public static void migrate(Database database, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        generateTempTables(database, daoClasses);

        for (int i = 0; i < daoClasses.length; i++) {
            DaoConfig daoConfig = new DaoConfig(database, daoClasses[i]);
            dropTable(database, true, daoConfig);
            createTable(database, false, daoConfig);
        }

        restoreData(database, daoClasses);
    }

    private static void dropTable(Database database, boolean ifExists, DaoConfig daoConfig) {
        String sql = String.format("DROP TABLE %s\"%s\"", ifExists ? "IF EXISTS " : "", daoConfig.tablename);
        database.execSQL(sql);
    }

    private static void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            String tempTableName = null;

            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
            String tableName = daoConfig.tablename;
            if (!isTableExists(db, false, tableName)) {
                continue;
            }
            try {
                tempTableName = daoConfig.tablename.concat("_TEMP");
                StringBuilder dropTableStringBuilder = new StringBuilder();
                dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";");
                db.execSQL(dropTableStringBuilder.toString());

                StringBuilder insertTableStringBuilder = new StringBuilder();
                insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName);
                insertTableStringBuilder.append(" AS SELECT * FROM "
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章