数据库升级的意义
我们在开发Android应用的时候,不可避免地要使用数据库。而数据库的结构在第一版的时候定下来,之后发布功能更新,或增加业务逻辑,原来的数据库结构可能就不适用了。而如果数据库的结构与之前版本的结构不同,新版本的应用读取旧数据库肯定会出问题。解决办法只有两种:
1.让用户卸载老版本再安装新的程序;
2.软件自行更新数据库结构。
第一种办法很明显不具备可操作性,而且用户一旦卸载软件,数据就丢失了,这是不能容忍的事情。因此,作为开发者必须妥善处理数据库的升级问题。
当然了,有的同学会说,这问题没意义嘛。我们在设计软件的时候就把数据库设计得完备一点就好了,一开始就考虑周全,以后再也不用管升级的事情。这种方法理论上虽然可行,但实际操作起来是非常困难的,除非你在开发定制软件(例如某些和硬件结合的产品,其硬件发布之后就不再更新或很少更新,这样的软件确实没多大改动)。对于面向市场的应用来说,很可能在立项之初根本不会知道以后会增加哪些功能。这样,我们终究还是要面对这个问题。
保留数据的升级
现在以一个假想的程序数据库来谈如何保留原有的数据库进行升级。为直观起见,这里在每次软件版本安装之后导出了数据库文件,并使用SQLite Studio显示表结构和内容,过程从略。并且为了代码的简洁,省略了一些异常处理。我们假设数据库有这样三个版本:
v1:t_user(username, password);
v2:t_user(username, password),t_region(region, code);
v3:t_user(username, password),t_region(region, code, country);
可以看出,第一次升级增加了一张表,而第二次升级修改了表的定义。
创建和升级数据表的基本知识
我们在使用数据库之前,基本上会自定义一个类继承自SQLiteOpenHelper。该类的其中一个构造函数形式是这样的(另一个多出来一个DatabaseErrorHandler):
publicSQLiteOpenHelper(Context context, String name, CursorFactory factory,intversion) {this(context, name, factory, version,null); }
这个构造函数里面的version参数即是我们设定的版本号。第一次使用数据库时传递的这个版本将被系统记录,并调用SQLiteOpenHelper#onCreate()方法进行建表操作。后续传入的版本如果比这个高,则会调用SQLiteOpenHelper#onUpgrade()方法进行升级。
增加一张表
很明显,增加新表(或者删除没有外键的表)的操作代价很小,只需要在onUpgrade()中写好建表操作和插入初始数据就好了。
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {if (oldVersion==1){db.execSQL("CREATETABLEt_region(_idintegerprimarykey"+ "autoincrement, regionvarchar, codevarchar)");//insert data...}}
从上面的图里可以看到,新版本的数据库中已经有t_region表了。
修改表定义
SQLite数库对ALTER TABLE命令支持非常有限,只能在表末尾添加列,不能修改列定义,不能删除已有的列。那么如果要修改表呢?我们可以采用临时表的办法。具体来说有四步:
将现有表重命名为临时表;