Android数据库升级解决方案

1、SQLiteOpenHelper介绍

    SQLiteOpenHelper有两个方法, public void onCreate(SQLiteDatabase db)以及public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)。第一次安装App时onCreate(SQLiteDatabase db)会被系统回调,一般在onCreate(SQLiteDatabase db)中建立数据表;当数据库版本升级时,系统会回调onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),一般在onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)中作数据库升级方案。数据库的版本号在SQLiteOpenHelper的构造方法中传入。java

2、数据库升级方案

一、onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)详细介绍

在建立SQLiteOpenHelper时传入的数据库版本号若是大于当前版本App数据库文件的版本号onUpgrade会被系统回调。oldVersion为当前版本App数据库文件的版本号, newVersion为SQLiteOpenHelper传入的数据库版本号,newVersion确定大于oldVersion。数据库

二、举例说明

假设App已经发版过V一、V2,即将发版V3。V1建立了数据表feedback,数据库版本为1;V2在V1的feedback基础上增长了一个字段username,数据库版本为2;V3在V2的基础上新增了一个表crash,数据库版本为3。V1发版时SQLiteOpenHelper以下:dom

public class DBOpenHelper extends SQLiteOpenHelper {
    private static final String TAG = DBOpenHelper.class.getSimpleName();

    public DBOpenHelper(Context context) {
        super(context, "feedback.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        LogUtil.log(TAG, "onCreate");
        String createSql = "create table feedback (" +
                "  online integer," +
                "  speechtype integer," +
                "  priority integer ," +
                "  domain char(100)," +
                "  keyparams char(200)," +
                "  success integer," +
                "  errorcode integer," +
                "  errormsg char(100)," +
                "  network integer," +
                "  networktype integer," +
                "  ip char(32)," +
                "  userid char(100)," +
                "  userphone char(20)," +
                "  useraddress char(200)," +
                "  starttime bigint," +
                "  finishtime bigint" + ")";
        db.execSQL(createSql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        LogUtil.log(TAG, "onUpgrade");
    }

}

V2须要将feedback增长一个字段username,用户从V1升级到V2时,须要改变库表结构而且将原来的feedback进行迁移,V2发版时SQLiteOpenHelper以下:ide

public class DBOpenHelper extends SQLiteOpenHelper {
    private static final String TAG = DBOpenHelper.class.getSimpleName();

    public DBOpenHelper(Context context) {
        super(context, "feedback.db", null, 2);
    }

    /**
     * 新增字段username
     * @param db
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        LogUtil.log(TAG, "onCreate");
        String createSql = "create table feedback (" +
                "  online integer," +
                "  speechtype integer," +
                "  priority integer ," +
                "  domain char(100)," +
                "  keyparams char(200)," +
                "  success integer," +
                "  errorcode integer," +
                "  errormsg char(100)," +
                "  network integer," +
                "  networktype integer," +
                "  ip char(32)," +
                "  userid char(100)," +
                "  username char(100),"+
                "  userphone char(20)," +
                "  useraddress char(200)," +
                "  starttime bigint," +
                "  finishtime bigint" + ")";
        db.execSQL(createSql);
    }

    /**
     * 用户从V1升级到V2时改变库表结构并将V1数据库中的数据进行迁移
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        LogUtil.log(TAG, "onUpgrade");
        if (oldVersion==1) {//用户当前是V1版本
            //重命名
            String rename = "alter TABLE feedback RENAME TO feedback_temp";
            db.execSQL(rename);
            //创建新表
            onCreate(db);
            //数据拷贝
            String copy = "insert into feedback(online,speechtype,priority,domain,keyparams,success,errorcode,errormsg,network,networktype,ip,userid,userphone,useraddress,starttime,finishtime) " +
                    "select (online,speechtype,priority,domain,keyparams,success,errorcode,errormsg,network,networktype,ip,userid,userphone,useraddress,starttime,finishtime) from feedback_temp";
            db.execSQL(copy);
            //删除原表
            String delete = "drop table feedback_temp";
            db.execSQL(delete);
        }
    }

}

V3在V2的基础上增长了表crash,用户升级方案多是:V1-V2,V1-V3,V2-V3,V3发版时SQLiteOpenHelper以下:code

public class DBOpenHelper extends SQLiteOpenHelper {
    private static final String TAG = DBOpenHelper.class.getSimpleName();

    public DBOpenHelper(Context context) {
        super(context, "feedback.db", null, 3);
    }

    /**
     * 建表feedback、crash
     *
     * @param db
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        LogUtil.log(TAG, "onCreate");
        String createFeedbackSql = "create table feedback (" +
                "  online integer," +
                "  speechtype integer," +
                "  priority integer ," +
                "  domain char(100)," +
                "  keyparams char(200)," +
                "  success integer," +
                "  errorcode integer," +
                "  errormsg char(100)," +
                "  network integer," +
                "  networktype integer," +
                "  ip char(32)," +
                "  userid char(100)," +
                "  username char(100)," +
                "  userphone char(20)," +
                "  useraddress char(200)," +
                "  starttime bigint," +
                "  finishtime bigint" + ")";
        String createCrashSql = "create table crash (starttime bigint,finishtime bigint)";
        db.execSQL(createFeedbackSql);
        db.execSQL(createCrashSql);
    }

    /**
     * 升级方案可能为V1-V2;V1-V3;V2-V3
     *
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        LogUtil.log(TAG, "onUpgrade");
        switch (oldVersion) {
            case 1://用户当前是V1版本
                if (newVersion == 2) {//升级到V2
                    upgradeToV2(db);
                } else if (newVersion == 3) {//升级到V3
                    upgradeToV2(db);
                    upgradeToV3(db);
                }
                break;

            case 2://用户当前是V2版本
                if (newVersion == 3) {//升级到V3
                    upgradeToV3(db);
                }
                break;
        }

    }

    private void upgradeToV2(SQLiteDatabase db) {
        //重命名
        String rename = "alter TABLE feedback RENAME TO feedback_temp";
        db.execSQL(rename);
        //创建新表
        String createFeedbackSql = "create table feedback (" +
                "  online integer," +
                "  speechtype integer," +
                "  priority integer ," +
                "  domain char(100)," +
                "  keyparams char(200)," +
                "  success integer," +
                "  errorcode integer," +
                "  errormsg char(100)," +
                "  network integer," +
                "  networktype integer," +
                "  ip char(32)," +
                "  userid char(100)," +
                "  username char(100)," +
                "  userphone char(20)," +
                "  useraddress char(200)," +
                "  starttime bigint," +
                "  finishtime bigint" + ")";
        db.execSQL(createFeedbackSql);

        //数据拷贝
        String copy = "insert into feedback(online,speechtype,priority,domain,keyparams,success,errorcode,errormsg,network,networktype,ip,userid,userphone,useraddress,starttime,finishtime) " +
                "select * from feedback_temp";
        db.execSQL(copy);
        //删除原表
        String delete = "drop table feedback_temp";
        db.execSQL(delete);
    }

    private void upgradeToV3(SQLiteDatabase db) {
        String createCrashSql = "create table crash (starttime bigint,finishtime bigint)";
        db.execSQL(createCrashSql);
    }

}