在android开发中,app版本迭代过多,不可避免的有Sqlite数据库升级和降级的操作.当我们通过SqliteOpenHelper获得一个SqliteDatabase实例的时候,他内部会判断版本号, 调用对应的升级操作和降级操作.抽象类的升级回调方法是一个抽象方法, 降级回调方法直接抛出一个RuntimeException异常.所以,碰到这个问题我们要注意复写升级和降级的逻辑.
我们以升级为例,假设在本10000是初试版本创建一个person表,里面有name age local 三个字段,在10010版本增加一个phone字段,在10020版本将local字段改为country字段
我们首先要明确以下问题:
1,android中Sqlite数据库提供给数据表增加字段功能,但是不同删除字段和更改字段名称的功能. 所以要删除表字段和更改表字段名称需要进行数据迁移
2, 要考虑平滑升级
例如:10000可以直接平滑升级到10010,还要考虑到 10000跨版本平滑升级到10020
3,升级过程涉及到数据的迁移 ,可能数据量比较大也比较复杂,所以我们要开启事务,要么成功要么失败回滚
4,一个数据表的迁移步骤为
A,创建一个要更改字段的原来了的数据表名称更改
B,创建一个新表,新的字段,表明与原表一致
C,将旧表的数据迁移到新表
D,删除旧表
实现上面需求的代码如下:
public class DBHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 10000;
private static final String DATABASE_NAME = "demo.db";
// 初试版本(第一个版本)创建一张表
private static final String SQL_CREATE_PERSON_TABLE = "CREATE TABLE person (name TEXT, age TEXT, loacal TEXT)";
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_PERSON_TABLE);
}
// 在数据库升级和降级的时候,建议开启事务,这样要成功都成功,不成功就全不成功,维持现状,这样避免脏数据
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 第二个版本给初始表加一个字段phone
if (oldVersion == 10000) {
String sql = "ALTER TABLE person ADD phone TEXT";
db.execSQL(sql);
Log.i("tag", "版本升级了 " + "oldVersion = " + oldVersion+ " newVersion = " + newVersion);
//重新设置oldVersion为了跨版本的平滑升级
oldVersion = 10010;
}
/*
* 第三个版本给person表中的local字段改名为country 由于sqlite数据库不支持对表中字段名的删除,
* 更名.所以我们需要重新创建一张表, 把原表中的数据备份过去,然后将原表删除即可
*/
if (oldVersion == 10010) {
Log.i("tag", "版本升级了 " + "oldVersion = " + oldVersion
+ " newVersion = " + newVersion);
String alterTableSql = "alter table person rename to tempPerson";
String createNewTableSql = "create table person (name TEXT, age TEXT, country TEXT,phone TEXT) ";
// step 1:原表person更名为tempPerson
db.execSQL(alterTableSql);
// step 2: 创建新的person表
db.execSQL(createNewTableSql);
// step 3: 原来表的数据迁移到新表
String backupSql = "insert into person select * from tempPerson ";
db.execSQL(backupSql);
// step 4: 删除临时表 tempPerson
String deleteSql = "DROP table tempPerson";
db.execSQL(deleteSql);
}
}
}
下面给出源码链接, 当使用demo测试的时候,只需要将版本号使用10000,10010,10020更改即可