SQLite数据库版本升级
应用上线后会不断维护和更新版本,应用中使用数据库时,应用的升级难免会牵扯到数据库的升级。假如应用从V1.0更新到V2.0,到现在的V3.0。V1.0版本中只有一张Product商品表。到V2.0版本时,Product中需要增加一个字段salesperson。到V3.0时,增加了一张Shop表。那么需要考虑一个问题,应用的用户很多,有老用户,有新用户。用户使用可能使用不同版本的应用,现在有了V3.0版本。那么可能有新用户直接安装V3.0。可能有从V2.0更新到V3.0的,也可能有V1.0更新到V3.0的。我们知道SQLiteOpenHelper类有onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)方法。onCreate()方法是在数据库版本号为0的时候调用,只调用一次。onUpgrade()方法是数据库版本更新的时候调用。
正常情况下:
- 直接安装V3.0,只走onCreat();不走onUpgrade()。
- V1.0 - V3.0,只走onUpgrade(),不走onCreat()。
- V2.0 - V3.0,只走onUpgrade(),不走onCreat()。
那么表的更新放在哪个方法中呢?但是想想,要么放在onCreat()方法要么onUpgrade()中。
如果直接安装V3.0,那么可以完全放在onCreat()中。因为onUpgrade()方发不能被调用,所以需要全部写在onCreat()方法中。但是考虑到V1.0 —>V3.0或V2.0 —>V3.0时onCreat()不能在被调用了,所以更新部分不能写在onCreat()中,对于V1.0 —>V3.0或V2.0 —>V3.0更新可以写在onUpgrade()方法中,因为onUpgrad()方发得到调用。
既然不能完全写在onCreat()中,那么能全部写在onUpgrade()方法中吗?对于V1.0 —>V3.0或V2.0 —>V3.0的更新Product表已经存在了,所以不需要在创建Product表了,而是需要更新它,所以更新部分需要写在onUpgrad()方法中。即不能全部的代码写在onUpgrade()方法中。
考虑到各种情况,不能完全写在onCreat()方法中,也不能完全写在onUpgrade()方法中,经过上面的分析,更新部分一定需要写在onUpgrade()方法中。但时,onUpgrade()方法只在数据库版本升级后才被调用啊,在直接安装V3.0的时候不被调用,那怎么办?我们可以手动调用啊。(哈哈哈,问题解决)。那在哪里调用呢?当然是在onCreat()方法中调用。
经过上面的分析,数据库更新部分是写在onUpgrade()方发中的。首次创建数据库时,需要创键的表可以下在onCreat()方法中。这是符合以前思路的。上面分析的关键点在于,在onCreat()方法中手动调用一次onUpgrade()方法。这是思维的突破,以前总是认为onUpgrade()只能在数据库版本升级时由系统调用。这样把数库更新的部分放在onUpgrade()方法中。由于在onCreat()方法中手动调用了一次onUpgrade()方法,所以直接直接安装V3.0的版本的用户,数库更新部分的代码也会被执行。而从V1.0—>V3.0版本和V2.0—>V3.0的,onCreat()不会被调用,但由于数据库版本升级了,所以onUpgrade()方法会被调用。
接下来看代码:先看DBOpenHelper类
public class DBOpenHelper extends SQLiteOpenHelper {
private Context mContext ;
public static String batabaseName = "message.db";
public static String tableName = "message" ;
public static String product_name = "product_name";
public static String product_type = "product_type";
public static String sale_price = "sale_price";
public static String purcgase_price = "purcgase_price";
public static String regist_date = "regist_date";
public static String sendname = "sendname";
private final int INITIAL_VERSION = 1 ; // 初始版本号
public static int NEW_VERSION = 0 ; // 最新的版本号
/**
* 经测试发现version不能小于等于0 否则报错
* @param context
* @param name
* @param factory
* @param version
*/
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context ;
NEW_VERSION = version ;
}
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {
super(context, name, factory, version, errorHandler);
mContext = context ;
NEW_VERSION = version ;
}
@Override
public void onCreate(SQLiteDatabase db) {
String createTable = "create table if not exists "+ tableName + "( product_id char(4) primary key , product_name varchar(100) not null , product_type varchar(32) not null , " +
"sale_price int , purcgase_price int , regist_date date )";
db.execSQL(createTable);
Log.d("TAG" , "数据库创建");
onUpgrade( db , INITIAL_VERSION , NEW_VERSION );
}
@Override
public void onUpgrade( SQLiteDatabase db , int oldVersion , int newVersion ) {
update(db, oldVersion, newVersion);
}
/**
* 数据库版本递归更新
* @param oldVersion 数据库当前版本号
* @param newVersion 数据库升级后的最终版本号
*/
public void update(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.d("TAG" , "onUpgrade oldVersion = "+ oldVersion + " newVersion = "+ newVersion);
Upgrade upgrade = null;
if (oldVersion < newVersion) {
oldVersion++;
upgrade = VersionFactory.getUpgrade(oldVersion); // 重点
if (upgrade == null) {
return;
}
upgrade.update(db);
update(db, oldVersion, newVersion); // 递归调用
}
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
super.onDowngrade(db, oldVersion, newVersion);
Log.d("TAG" , "onDowngrade oldVersion = "+ oldVersion + " newVersion = "+ newVersion);
}
}
DBOpenHelper继承SQLiteOpenHelper类。onCreate()方法调用了onUpgrade()方法。update()方法主要负责版本更新了,里面使用了到了递归调用。VersionFactory类是生产Upgrade类的工厂类。代码如下:
public class VersionFactory {
static Set<String> list = new LinkedHashSet<>();
static { // 以后没添加一个版本,就在这个集合中添加类的全路径(必须是全路径)
list.add("com.dbsql.db.VersionSecond");
list.add("com.dbsql.db.VersionThird");
}
/**
* 根据数据库版本号获取对应的对象
* @param i
* @return
*/
public static Upgrade getUpgrade(int i) {
Upgrade upgrade = null ;
if (null != list && list.size() > 0) {
try {
for (String className : list) {
Class<?> cls = null;
cls = Class.forName(className);
if (Upgrade.class == cls.getSuperclass()) { // 首先父类是Upgrade类
VersionCode versionCode = cls.getAnnotation(VersionCode.class);
if (null == versionCode) {
throw new IllegalStateException(cls.getName() + "类必须使用VersionCode类注解");
} else {
if (i == versionCode.value()) { // 等于当前要操作的版本。
upgrade = (Upgrade) cls.newInstance(); // 根据class获取实例,并向上转为父类型。
break;
}
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new IllegalStateException("没有找到类名,请检查list里面添加的类名是否正确!");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return upgrade;
}
/**
* 得到当前数据库版本
* @return
*/
public static int getCurrentDBVersion() {
return list.size() + 1;
}
}
/**
*注解类
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface VersionCode {
int value() default 1;
}
public abstract class Upgrade {
public abstract void update(SQLiteDatabase db);
}
/**
*第二版本要做的更新
*/
@VersionCode(2)
public class VersionSecond extends Upgrade {
@Override
public void update(SQLiteDatabase db) {
String sql = "alter table "+DBOpenHelper.tableName + " add column salesperson char(10) " ;
db.execSQL(sql);
}
}
/**
*第三版本要做的更新
*/
@VersionCode(3)
public class VersionThird extends Upgrade{
@Override
public void update(SQLiteDatabase db) {
String sql = "create table if not exsits Shop ( shop_id char(4) primary key , shop_name text )" ;
db.execSQL(sql);
}
}
V1.0—>V3.0的过程是,先从V1.0—>V2.0,再从V2.0—>V3.0。
V2.0—>V3.0的过程是,从V2.0—>V3.0。
直接安装V3.0版本的过程是,先常见V1.0版本的表,从V1.0—>V2.0,最后从V2.0—>V3.0。