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 "
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章