GreenDao数据库升级问题

作者: Bear_android | 来源:发表于2017-05-17 16:35 被阅读520次

前面博客中有介绍轻量级的数据库GreenDao的整合。本文介绍如何对GreenDao数据库进行升级。

为什么要进行数据库升级呢?

在项目建立之初,数据库的表结构基本上以满足现阶段的业务而建立,随着后面业务的增加需要更多的column,或者废弃掉表中的某些column,此时如果直接去修改表结构,就会与之前已有的表冲突,导致Crash,此时我们就需要升级数据库中的表。

数据库升级的思路

删除重建

这种方法是最简单直接的。直接将之前的数据库删除后,再重新建立数据库。这样会使得之前保存的数据丢失。不需要持久化的保存数据,可以采用这种方式。

逐级版本迭代升级

比如当前版本为1,最新版本为3,此方案就是先从1–>2–>3. 这种方法实际应用中用起来相当的繁琐,要维护每个版本,所以不做过多介绍。

备份数据库,建立新数据库,然后将备份导入

如题,,奖原来的表删除,之后再将临时表插入到新建的表之中,然后再将临时表给删除了。以此完成数据迁移。

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

对比原表,增加或者删除column

代码实现

首先创建一个数据库帮助类

/**
 * 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的版本号,在内层的gradle中的buildTypes节点下添加

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

以下是更新方式:

  1. 删除再新建
 /**
     * 删除原表重新再建立一个表
     * @param db
     */
    public void dropAndCreate(Database db){
        DaoMaster.dropAllTables(db, true);
        DaoMaster.createAllTables(db, false);
    }
  1. 备份数据库,建立新数据库,然后将备份导入
/**
     * 备份还原
     * @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);
    }
    /**
     * 数据库备份
     * @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());
        }
    }
    /**
     * 数据库恢复
     * @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());
         }
        }
    }

下面贴出,完整的数据库升级帮助类

/**
 * 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);
    }

    /**
     * 数据库备份
     * @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());
        }
    }

    /**
     * 数据库恢复
     * @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;
    }
}

以上是本人自己整理的一些升级方法,请大家批评指正。

相关文章

  • GreenDao简单使用和数据库升级

    一 GreenDao的配置 学习/参考地址:GreenDao3.0数据库的简单使用GreenDAO数据库升级 1、...

  • android GreenDao

    Android框架之路——GreenDao3.2.2的使用 - CSDN博客 GreenDAO 完美解决数据库升级...

  • GreenDao数据库升级问题

    前面博客中有介绍轻量级的数据库GreenDao的整合。本文介绍如何对GreenDao数据库进行升级。 为什么要进行...

  • 2019-06-05 数据库升级

    数据库升级 在实际开发当中,我们经常要对数据库进行升级,但GreenDAO默认的DaoMaster.DevOpen...

  • GreenDao数据库升级

    GreenDao数据库升级 第1步:升级数据库版本号 第2步:修改数据库实体类 第3步:迁移数据库 注:数据库升级...

  • 数据库操作能力 -- GreenDao -- 2

    七、数据库的升级 GreenDao的OpenHelper下有个onUpgrade(Database db, int...

  • GreenDao 使用过程中遇到的问题

    最近开发app的时候由于会用到数据库所以采用了开源库GreenDao,于是开启了采坑之旅 1、greendao升级...

  • Android十八章:是时候在你项目用上greenDAO3

    GreenDao GreenDao3.1.0使用案例包含(增删查改,升级数据库),3.+版本比2.+更加便捷生成D...

  • GreenDao版本升级

    最近项目中用到了GreenDao,碰到了版本升级的问题。自己写数据库的时候都是自定义的helper,用GreenD...

  • GreenDao日常踩坑

    项目使用到Greendao当做数据库,升级的时候遇到个问题,但新添加int类型字段的时候,数据迁移报错了,查看到是...

网友评论

  • WDL:楼主有没有试过,单表数据达到百万千万级别的时候,这种方法的时效问题?
    Bear_android:那要看你是什么情况升级数据库的呢,如果是增加字段的话,直接向表中增加就好了,如果是修改了结构这种。需要保存前面数据的只能做备份还原,如果不需要之前数据,可以删表重建。我只是提供了一些思路,具体存表删表你可以自己根据需求加一些策略,比如分批次存取,按照时间建立优先级等等···

本文标题:GreenDao数据库升级问题

本文链接:https://www.haomeiwen.com/subject/rzidxxtx.html