在app版本升级时,同时升级了Sqlite数据库的版本号的话,如果需要保留之前的数据,需要在onUpgrade方法中做处理。这里记录一下在onUpgrade处理升级的时候的一些注意事项。
先看下常用的SQLiteOpenHelper的方法:
public class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
/**
* 1、在第一次打开数据库的时候才会走
* 2、在清除数据之后再次运行-->打开数据库,这个方法会走
* 3、没有清除数据,不会走这个方法
* 4、数据库升级的时候这个方法不会走
*/
@Override
public void onCreate(SQLiteDatabase db) {
}
/**
* 1、这个方法只有当数据库已经存在,而且版本升高的时候,才会调用
* 2、第一次创建数据库的时候,这个方法不会走
* 3、清除数据后再次运行(相当于第一次创建)这个方法也不会走
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
如果第一次的数据库版本为1,现在升级之后版本为2,即当前app版本比上次的app版本中的数据库的版本号高1级,也有可能是3升4, 4升5这样的,先看下这时的处理有几种情况要考虑:
1. 摒弃之前的表并重新创建该表
这种情况一般是数据库中的数据可能是一些无关紧要的临时数据,处理比较简单粗暴,直接删除重建,且表的结构跟之前完全一样。不过应该很少有采用这种方式的吧。
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1://这里的数值是上次的版本,也就是针对上次的版本,本次的版本要做哪些改变
db.execSQL("DROP TABLE IF EXISTS " + TableEvent.TABLE_NAME);
db.execSQL(TableEvent.CREATE_SQL);
default:
break;
}
}
2. 在之前基础上创建新的表
这种情况也比较简单,主要是新版比之前的版本创建新的表,而且这个表跟之前的表没有什么关系。这时同时也要在onCreate中加上执行创建的sql(针对新用户)。
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1://这里的数值是上次的版本,也就是针对上次的版本,本次的版本要做哪些改变
//这种情况需要同时在onCreate中加上执行新表的创建sql(针对新用户)
db.execSQL(xxxxx);
default:
break;
}
}
3. 在老表基础上新增字段
这种情况需要修改老的表新增字段
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1://这里的数值是上次的版本,也就是针对上次的版本,本次的版本要做哪些改变
//这种情况需要同时在onCreate中加上执行新增字段的创建表sql(针对新用户)
db.execSQL("ALTER TABLE TableEvent.CREATE_SQL ADD COLUMN TableEvent.xxx VARCHAR(255)");
default:
break;
}
}
4. 数据库升级时保留老的数据并同步到新的表当中
这种情况是新表保留老表的字段结构情况
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1://这里的数值是上次的版本,也就是针对上次的版本,本次的版本要做哪些改变
//老的表重命名
String CREATE_TEMP_BOOK = "alter table book rename to _temp_book";
//创建新的表,表名跟原来一样,并保留原来的字段
String CREATE_BOOK = "create table book(bookId integer primarykey, bookName text);";
//将重命名后的老表中的数据导入新的表中
String INSERT_DATA = "insert into book select *,'' from _temp_book";
//删除老表
String DROP_BOOK = "drop table _temp_book";
db.execSQL(CREATE_TEMP_BOOK);
//这句要同时放到onCreate中,针对新用户
db.execSQL(CREATE_BOOK);
db.execSQL(INSERT_DATA);
db.execSQL(DROP_BOOK);
default:
break;
}
}
5. 新表跟以前的表字段结构完全不一样
这种情况是新表跟以前字段结构完全不一样或者说有大部分的差异,跟上面第4种处理差不多,但是需要手动查询老表的某些字段的数据然后插入的新表的对应字段,最后删除老表即可。
前面几种情况是单级升级的时候,针对上次的版本本次的版本需要做的处理,如果是跨级升级,比如用户app很久没有更新了,这次升级数据库版本从1升到了3,或者2升到了6,这时需要分开处理每次的版本:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL(CREATE_TBL_CATEGORY) // 建立新表
case 2:
db.execSQL("ALTER TABLE Book ADD COLUMN category_id INTEGER"); // 增加字段
case 3:
//同步老的数据到新的表
String CREATE_TEMP_BOOK = "alter table book rename to _temp_book";
String CREATE_BOOK = "create table book(bookId integer primarykey, bookName text);";
String INSERT_DATA = "insert into book select *,'' from _temp_book";
String DROP_BOOK = "drop table _temp_book";
db.execSQL(CREATE_TEMP_BOOK);
db.execSQL(CREATE_BOOK);
db.execSQL(INSERT_DATA);
db.execSQL(DROP_BOOK);
default:
break;
}
}
注意,这里OnUpgrade() 方法中的 switch 语句是没有 break 的,会一直执行到语句结束。为什么要这么写想想就明白了。比如用户手上的版本是 1,新版 App 的版本是 5,那么就会有 4 个版本的数据库升级,switch() 自然不能中途 break,必须执行这 4 个版本的数据库升级语句。同时每次的case中添加的创建新表的sql代码不要忘了在onCreate中同时添加,因为新用户也是要执行的。
这样的好处是每次更新数据库的时候只需要在onUpgrade方法的末尾加一段从上个版本升级到新版本的代码,易于理解和维护。但是如果版本跨级比较多,这个地方可能比较费时了,建议在可控的版本差之内强制app版本升级。
参考:
https://blog.csdn.net/xx326664162/article/details/50311717
https://www.cnblogs.com/xgjblog/p/5647803.html