Android学习笔记(十八)——再谈升级数据库
//此系列博文是《第一行Android代码》的学习笔记,如有错漏,欢迎指正!
之前我们为了保证数据库中的表是最新的,只是简单地在 onUpgrade()方法中删除掉了当前所有的表,然后强制重新执行了一遍 onCreate()方法。这种方式在产品的开发阶段确实可以用,但是当产品真正上线了之后就绝对不行了。想象以下场景,比如你编写的某个应用已经成功上线,并且还拥有了不错的下载量。现在由于添加新功能的原因,使得数据库也需要一起升级,然后用户更新了这个版本之后发现以前程序中存储的本地数据全部丢失了。
所以我们需要进行一些合理的控制,保证在升级数据库的时候数据不会丢失。我们知道,每一个数据库版本都会对应一个版本号, 当指定的数据库版本号大于当前数据库版本号的时候, 就会进入到 onUpgrade()方法中去执行更新操作。所以我们可以在这里为每一个版本号赋予它各自改变的内容,然后在onUpgrade()方法中对当前数据库的版本号进行判断,再执行相应的改变就可以了。
下面我们来进入实践:
一、Mission One: 在数据库中添加一张Book表
这个比较简单,MyDatabaseHelper代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class MyDatabaseHelper extends SQLiteOpenHelper {
2 public static final String CREATE_BOOK = "create table Book ("
3 + "id integer primary key autoincrement, "
4 + "author text, "
5 + "price real, "
6 + "pages integer, "
7 + "name text)";
8 public MyDatabaseHelper(Context context, String name, CursorFactory
9 factory, int version) {
10 super(context, name, factory, version);
11 }
12 @Override
13 public void onCreate(SQLiteDatabase db) {
14 db.execSQL(CREATE_BOOK);
15 }
16 @Override
17 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
18 }
19 }
二、Mission Two:向数据库中再添加一张 Category表
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class MyDatabaseHelper extends SQLiteOpenHelper {
2 public static final String CREATE_BOOK = "create table Book ("
3 + "id integer primary key autoincrement, "
4 + "author text, "
5 + "price real, "
6 + "pages integer, "
7 + "name text)";
8 public static final String CREATE_CATEGORY = "create table Category ("
9 + "id integer primary key autoincrement, "
10 + "category_name text, "
11 + "category_code integer)";
12
13 public MyDatabaseHelper(Context context, String name,CursorFactory factory, int version) {
14 super(context, name, factory, version);
15 }
16
17 @Override
18 public void onCreate(SQLiteDatabase db) {
19 db.execSQL(CREATE_BOOK);
20 db.execSQL(CREATE_CATEGORY);
21 }
22
23 @Override
24 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
25 switch (oldVersion) {
26 case 1:
27 db.execSQL(CREATE_CATEGORY);
28 default:
29 }
30 }
31 }
可以看到,在 onCreate()方法里我们新增了一条建表语句,然后又在 onUpgrade()方法中添加了一个 switch 判断,如果用户当前数据库的版本号是 1,就只会创建一张 Category表。这样当用户是直接安装的第二版的程序时,就会将两张表一起创建。而当用户是使用第二版的程序覆盖安装第一版的程序时,就会进入到升级数据库的操作中,此时由于 Book 表已经存在了,因此只需要创建一张 Category表即可。
三、Misson Three:在 Book表中添加一个 category_id 的字段
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class MyDatabaseHelper extends SQLiteOpenHelper {
2 public static final String CREATE_BOOK = "create table Book ("
3 + "id integer primary key autoincrement, "
4 + "author text, "
5 + "price real, "
6 + "pages integer, "
7 + "name text, "
8 + "category_id integer)";
9 public static final String CREATE_CATEGORY = "create table Category ("
10 + "id integer primary key autoincrement, "
11 + "category_name text, "
12 + "category_code integer)";
13
14 public MyDatabaseHelper(Context context, String name,CursorFactory factory, int version) {
15 super(context, name, factory, version);
16 }
17
18 @Override
19 public void onCreate(SQLiteDatabase db) {
20 db.execSQL(CREATE_BOOK);
21 db.execSQL(CREATE_CATEGORY);
22 }
23 @Override
24 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
25 switch (oldVersion) {
26 case 1:
27 db.execSQL(CREATE_CATEGORY);
28 case 2:
29 db.execSQL("alter table Book add column category_id integer");
30 default:
31 }
32 }
33 }
首先我们在 Book 表的建表语句中添加了一个 category_id 列,这样当用户直接安装第三版的程序时,这个新增的列就已经自动添加成功了。然而,如果用户之前已经安装了某一版本的程序, 现在需要覆盖安装, 就会进入到升级数据库的操作中。 在 onUpgrade()方法里,我们添加了一个新的 case,如果当前数据库的版本号是 2,就会执行 alter命令来为Book 表新增一个 category_id 列。
这里有一点需要注意:switch 中每一个 case 的最后都是没有使用 break的。这样做的原因是为了保证在跨版本升级的时候, 每一次的数据库修改都能被全部执行到。比如用户当前是从第二版程序升级到第三版程序的,那么 case 2中的逻辑就会执行。而如果用户是直接从第一版程序升级到第三版程序的,那么 case 1 和 case 2 中的逻辑都会执行。使用这种方式来维护数据库的升级,不管版本怎样更新,都可以保证数据库的表结构是最新的,而且表中的数据也完全不会丢失了。
//End.