GreenDao數(shù)據(jù)庫升級問題

前面博客中有介紹輕量級的數(shù)據(jù)庫GreenDao的整合。本文介紹如何對GreenDao數(shù)據(jù)庫進行升級咆畏。

為什么要進行數(shù)據(jù)庫升級呢?

在項目建立之初,數(shù)據(jù)庫的表結(jié)構(gòu)基本上以滿足現(xiàn)階段的業(yè)務而建立践宴,隨著后面業(yè)務的增加需要更多的column,或者廢棄掉表中的某些column,此時如果直接去修改表結(jié)構(gòu)爷怀,就會與之前已有的表沖突阻肩,導致Crash,此時我們就需要升級數(shù)據(jù)庫中的表运授。

數(shù)據(jù)庫升級的思路

刪除重建

這種方法是最簡單直接的烤惊。直接將之前的數(shù)據(jù)庫刪除后,再重新建立數(shù)據(jù)庫吁朦。這樣會使得之前保存的數(shù)據(jù)丟失柒室。不需要持久化的保存數(shù)據(jù),可以采用這種方式逗宜。

逐級版本迭代升級

比如當前版本為1雄右,最新版本為3不脯,此方案就是先從1–>2–>3. 這種方法實際應用中用起來相當?shù)姆爆崳S護每個版本复局,所以不做過多介紹亿昏。

備份數(shù)據(jù)庫角钩,建立新數(shù)據(jù)庫递礼,然后將備份導入

如題辫愉,将硝,獎原來的表刪除依疼,之后再將臨時表插入到新建的表之中律罢,然后再將臨時表給刪除了。以此完成數(shù)據(jù)遷移虫腋。

在原表基礎上直接添加新的column

對比原表,增加或者刪除column

代碼實現(xiàn)

首先創(chuàng)建一個數(shù)據(jù)庫幫助類

/**
 * description: GreenDao幫助類
 * author: bear .
 * Created date:  2017/5/17.
 */
public class MyOpenHelper extends DaoMaster.DevOpenHelper {


    public MyOpenHelper(Context context, String name) {
        super(context, name);
    }

    public MyOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }

    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
       /*此處不用super睛琳,因為父類中包含了
       dropAllTables(db, true);
        onCreate(db);
        需要自己定制升級
        */
    }
}

修改greenDao的版本號,在內(nèi)層的gradle中的buildTypes節(jié)點下添加

greendao{
            schemaVersion 1
         // 這個地方是自動生成的配置文件存放在哪個位置的
            targetGenDir 'src/main/java'
        }

以下是更新方式:

  1. 刪除再新建
 /**
     * 刪除原表重新再建立一個表
     * @param db
     */
    public void dropAndCreate(Database db){
        DaoMaster.dropAllTables(db, true);
        DaoMaster.createAllTables(db, false);
    }
  1. 備份數(shù)據(jù)庫,建立新數(shù)據(jù)庫黍少,然后將備份導入
/**
     * 備份還原
     * @param db
     * @param daoClasses
     */
    public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        generateTempTables(db, daoClasses);
        DaoMaster.dropAllTables(db, true);
        DaoMaster.createAllTables(db, false);
        restoreData(db, daoClasses);
    }
    /**
     * 數(shù)據(jù)庫備份
     * @param db
     * @param daoClasses
     */
    private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);

            String divider = "";
            String tableName = daoConfig.tablename;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            ArrayList<String> properties = new ArrayList<>();

            StringBuilder createTableStringBuilder = new StringBuilder();

            createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");

            for (int j = 0; j < daoConfig.properties.length; j++) {
                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tableName).contains(columnName)) {
                    properties.add(columnName);

                    String type = null;

                    try {
                        type = getTypeByClass(daoConfig.properties[j].type);
                    } catch (Exception exception) {
                    }

                    createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);

                    if (daoConfig.properties[j].primaryKey) {
                        createTableStringBuilder.append(" PRIMARY KEY");
                    }

                    divider = ",";
                }
            }
            createTableStringBuilder.append(");");

            db.execSQL(createTableStringBuilder.toString());

            StringBuilder insertTableStringBuilder = new StringBuilder();

            insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(") SELECT ");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(" FROM ").append(tableName).append(";");

            db.execSQL(insertTableStringBuilder.toString());
        }
    }
    /**
     * 數(shù)據(jù)庫恢復
     * @param db
     * @param daoClasses
     */
    private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);

            String tableName = daoConfig.tablename;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            ArrayList<String> properties = new ArrayList();

            for (int j = 0; j < daoConfig.properties.length; j++) {
                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tempTableName).contains(columnName)) {
                    properties.add(columnName);
                }
            }

            StringBuilder insertTableStringBuilder = new StringBuilder();

            insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(") SELECT ");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");

            StringBuilder dropTableStringBuilder = new StringBuilder();

            dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);

            db.execSQL(insertTableStringBuilder.toString());
            db.execSQL(dropTableStringBuilder.toString());
        }
    }
    private String getTypeByClass(Class<?> type) throws Exception {
        if (type.equals(String.class)) {
            return "TEXT";
        }
        if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
            return "INTEGER";
        }
        if (type.equals(Boolean.class)) {
            return "BOOLEAN";
        }

        Exception exception =
                new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
        throw exception;
    }

    private static List<String> getColumns(Database db, String tableName) {
        List<String> columns = new ArrayList<>();
        Cursor cursor = null;
        try {
            cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
            if (cursor != null) {
                columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
            }
        } catch (Exception e) {
            Log.v(tableName, e.getMessage(), e);
            e.printStackTrace();
        } finally {
            if (cursor != null) cursor.close();
        }
        return columns;
    }
  1. 對比表差異,向原表中直接插入column
/**
     * 對比差異访忿,在原表中直接添加column,贊不做刪除操作
     * @param db
     * @param daoClasses
     */
    public void contrastDiff(Database db,ArrayList<String>properties, Class<? extends AbstractDao<?, ?>>... daoClasses){
     for(int i=0;i<daoClasses.length;i++){
         DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
         String tableName=daoConfig.tablename;
         if(properties!=null&&properties.size()>0){
             ArrayList<String>tem=new ArrayList<>();
             StringBuilder sqlBuilder=new StringBuilder();
             for(int j=0;j<properties.size();j++){
                 if(getColumns(db,tableName).contains(properties.get(j))){
                     continue;
                 }
                 tem.add(properties.get(j));
             }
             sqlBuilder.append("INSERT INTO ").append(tableName).append(" (");
             sqlBuilder.append(TextUtils.join(",", tem));
             sqlBuilder.append(") SELECT ");
             sqlBuilder.append(TextUtils.join(",", tem));
             sqlBuilder.append(" FROM ").append(tableName).append(";");
             db.execSQL(sqlBuilder.toString());
         }
        }
    }

下面貼出,完整的數(shù)據(jù)庫升級幫助類

/**
 * description: greenDao升級幫助
 * author: bear .
 * Created date:  2017/5/17.
 */
public class MigrationHelper {

    private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION =
            "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
    private static MigrationHelper instance;

    public static MigrationHelper getInstance() {
        if (instance == null) {
            instance = new MigrationHelper();
        }
        return instance;
    }

    /**
     * 備份還原
     * @param db
     * @param daoClasses
     */
    public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        generateTempTables(db, daoClasses);
        DaoMaster.dropAllTables(db, true);
        DaoMaster.createAllTables(db, false);
        restoreData(db, daoClasses);
    }

    /**
     * 對比差異沼溜,在原表中直接添加column,贊不做刪除操作
     * @param db
     * @param daoClasses
     */
    public void contrastDiff(Database db,ArrayList<String>properties, Class<? extends AbstractDao<?, ?>>... daoClasses){
     for(int i=0;i<daoClasses.length;i++){
         DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
         String tableName=daoConfig.tablename;
         if(properties!=null&&properties.size()>0){
             ArrayList<String>tem=new ArrayList<>();
             StringBuilder sqlBuilder=new StringBuilder();
             for(int j=0;j<properties.size();j++){
                 if(getColumns(db,tableName).contains(properties.get(j))){
                     continue;
                 }
                 tem.add(properties.get(j));
             }
             sqlBuilder.append("INSERT INTO ").append(tableName).append(" (");
             sqlBuilder.append(TextUtils.join(",", tem));
             sqlBuilder.append(") SELECT ");
             sqlBuilder.append(TextUtils.join(",", tem));
             sqlBuilder.append(" FROM ").append(tableName).append(";");
             db.execSQL(sqlBuilder.toString());
         }
        }
    }

    /**
     * 刪除原表重新再建立一個表
     * @param db
     */
    public void dropAndCreate(Database db){
        DaoMaster.dropAllTables(db, true);
        DaoMaster.createAllTables(db, false);
    }

    /**
     * 數(shù)據(jù)庫備份
     * @param db
     * @param daoClasses
     */
    private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);

            String divider = "";
            String tableName = daoConfig.tablename;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            ArrayList<String> properties = new ArrayList<>();

            StringBuilder createTableStringBuilder = new StringBuilder();

            createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");

            for (int j = 0; j < daoConfig.properties.length; j++) {
                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tableName).contains(columnName)) {
                    properties.add(columnName);

                    String type = null;

                    try {
                        type = getTypeByClass(daoConfig.properties[j].type);
                    } catch (Exception exception) {
                    }

                    createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);

                    if (daoConfig.properties[j].primaryKey) {
                        createTableStringBuilder.append(" PRIMARY KEY");
                    }

                    divider = ",";
                }
            }
            createTableStringBuilder.append(");");

            db.execSQL(createTableStringBuilder.toString());

            StringBuilder insertTableStringBuilder = new StringBuilder();

            insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(") SELECT ");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(" FROM ").append(tableName).append(";");

            db.execSQL(insertTableStringBuilder.toString());
        }
    }

    /**
     * 數(shù)據(jù)庫恢復
     * @param db
     * @param daoClasses
     */
    private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);

            String tableName = daoConfig.tablename;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            ArrayList<String> properties = new ArrayList();

            for (int j = 0; j < daoConfig.properties.length; j++) {
                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tempTableName).contains(columnName)) {
                    properties.add(columnName);
                }
            }

            StringBuilder insertTableStringBuilder = new StringBuilder();

            insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(") SELECT ");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");

            StringBuilder dropTableStringBuilder = new StringBuilder();

            dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);

            db.execSQL(insertTableStringBuilder.toString());
            db.execSQL(dropTableStringBuilder.toString());
        }
    }

    private String getTypeByClass(Class<?> type) throws Exception {
        if (type.equals(String.class)) {
            return "TEXT";
        }
        if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
            return "INTEGER";
        }
        if (type.equals(Boolean.class)) {
            return "BOOLEAN";
        }

        Exception exception =
                new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
        throw exception;
    }

    private static List<String> getColumns(Database db, String tableName) {
        List<String> columns = new ArrayList<>();
        Cursor cursor = null;
        try {
            cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
            if (cursor != null) {
                columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
            }
        } catch (Exception e) {
            Log.v(tableName, e.getMessage(), e);
            e.printStackTrace();
        } finally {
            if (cursor != null) cursor.close();
        }
        return columns;
    }
}

以上是本人自己整理的一些升級方法游添,請大家批評指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市廊酣,隨后出現(xiàn)的幾起案子晓猛,更是在濱河造成了極大的恐慌凡辱,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異乳乌,居然都是意外死亡捧韵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門汉操,熙熙樓的掌柜王于貴愁眉苦臉地迎上來再来,“玉大人,你說我怎么就攤上這事磷瘤∶⑴瘢” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵膀斋,是天一觀的道長梭伐。 經(jīng)常有香客問我,道長仰担,這世上最難降的妖魔是什么糊识? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任绩社,我火速辦了婚禮,結(jié)果婚禮上赂苗,老公的妹妹穿的比我還像新娘愉耙。我一直安慰自己,他們只是感情好拌滋,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布朴沿。 她就那樣靜靜地躺著,像睡著了一般败砂。 火紅的嫁衣襯著肌膚如雪赌渣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天昌犹,我揣著相機與錄音坚芜,去河邊找鬼。 笑死斜姥,一個胖子當著我的面吹牛鸿竖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播铸敏,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼缚忧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了杈笔?” 一聲冷哼從身側(cè)響起闪水,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桩撮,沒想到半個月后敦第,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峰弹,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡店量,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鞠呈。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片融师。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蚁吝,靈堂內(nèi)的尸體忽然破棺而出旱爆,到底是詐尸還是另有隱情,我是刑警寧澤窘茁,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布怀伦,位于F島的核電站,受9級特大地震影響山林,放射性物質(zhì)發(fā)生泄漏房待。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桑孩。 院中可真熱鬧拜鹤,春花似錦、人聲如沸流椒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宣虾。三九已至惯裕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绣硝,已是汗流浹背轻猖。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留域那,地道東北人咙边。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像次员,于是被迫代替她去往敵國和親败许。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

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

  • 需要原文的可以留下郵箱我給你發(fā)淑蔚,這里的文章少了很多圖市殷,懶得網(wǎng)上粘啦 1數(shù)據(jù)庫基礎 1.1數(shù)據(jù)庫定義 1)數(shù)據(jù)庫(D...
    極簡純粹_閱讀 7,428評論 0 46
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,139評論 25 707
  • 1、引言 數(shù)據(jù)庫設計過程中表刹衫、字段等的命名規(guī)范也算是設計規(guī)范的一部分醋寝,不過設計規(guī)范更多的是為了確保數(shù)據(jù)庫設計的合理...
    SnowflakeCloud閱讀 40,999評論 0 48
  • 國家電網(wǎng)公司企業(yè)標準(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,970評論 6 13
  • 《那些日子》 那些日子、滿心滿眼都是 色彩带迟,晌午音羞、陽光一把一把撒向純凈的 畫面,散發(fā)著如珠的笑聲和 鮮花的芬芳仓犬。 ...
    紫薔薇簡書閱讀 1,155評論 14 21