Android Sqlite数据库跨版本升级 保存之前数据

转载请标明出处: http://blog.csdn.net/xx326664162/article/details/50311717 文章出自:薛瑄的博客

你也可以查看我的其他同类文章,也会让你有一定的收货!

Android 中SQLiteOpenHelper 的一个抽象函数

onUpgrade(SQLiteDatabase db,int oldVersion ,int newVersion)

数据库版本不断地迭代升级,根据oldVersion进行一些数据库方面的操作

优点:
1. 因为当前版本已经确定,如果使用newVersion版本进行比较没有意义,完全可以硬编码。所以使用oldVersion与指定数据库版本比较,更利于针对不同数据库版本的进行升级操作

两种数据库升级的处理方法:

1、逐级升级

迭代逐级升级,主要是考虑到夸版本升级,比如有的用户一直不升级版本,数据库版本号一直是1,而客户端最新版本其实对应的数据库版本已经是3了,那么我中途可能对数据库做了很多修改,可以迭代升级,方便代码理解和维护。

我所使用的方法:

  • 不使用for循环迭代升级,使用不带break的switch迭代升级
  • 增加新列,直接在表上新建列
  • 删除列或者更改一个已经存在的字段的名称、数据类型、限定符等等,要建立新表,将原表的数据复制到新表中

Sqlite如何修改表结构字段类型


建立新表,将原表的数据复制到新表中:

保留原来数据库数据
http://www.cnblogs.com/wang340/archive/2013/05/06/3063135.html
http://m.blog.csdn.net/article/details?id=50260401
http://87426628.blog.163.com/blog/static/6069361820131069485844/

这三篇博客思路:

  1. 将原表A改名为临时表B

  2. 创建新表C(名称与原表A一样)

  3. 导入数据到新表C  

  4. 删除临时表B


举个例子

有个图书管理相关的 App,有一张图书表 —— Book,其表结构如下

字段名 类型 说明
id INTEGER 主键
name TEXT 书名
author TEXT 作者
price INTEGER 价格
pages INTEGER 页数

第一版的 App,其 DBHelper 这么写

public class BookStoreDbHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "BookStore.db";

    private static final int VERSION = 1;

    private static final String CREATE_TBL_BOOK = "CREATE TABLE Book ("
        + "id INTEGER PRIMARY KEY AUTOINCREMENT, "
        + "name TEXT, "
        + "author TEXT, "
        + "prices INTEGER, "
        + "pages INTEGER"
        + ")";

    public BookStoreDbHelper(Context context) {
        this(context, null, null, 0);
    }

    private BookStoreDbHelper(Context context, String name, CursorFactory factory,
        int version) {
        super(context, DB_NAME, null, VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_TBL_BOOK);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }

}

几个星期之后,第二版的需求来了,需要增加一个书籍分类表 —— Category,其表结构如下:

字段名 类型 说明
id INTEGER 主键
category_name TEXT 分类名称
category_code INTEGER 分类代码

这个时候,就需要对数据库进行升级,增加一张表。这时候一个问题就来了:

如何在不影响旧版本 App 稳定性的情况下,对数据库进行升级?

先来看看代码实现,等下再细说为什么这么做。

代码实现如下

private static final int VERSION = 2;  // 版本号加 1

// Categroy 建表语句
private static final String CREATE_TBL_CATEGORY = "CREATE TABLE Category ("
    + "id INTEGER PRIMARY KEY AUTOINCREMENT, "
    + "category_name TEXT, "
    + "category_code INTEGER"
    + ")";

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_TBL_CATEGORY)
    db.execSQL(CREATE_TBL_BOOK);  // 建立新表
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    switch (oldVersion) {
        case 1:
            db.execSQL(CREATE_TBL_CATEGORY)  // 建立新表
        default:
            break;
    }
}

现在来说说为什么这么写。
注意到一点,这是第二版的 App,那么就会有两种用户:

  • 之前没有安装过这款 App,安装时是全新安装。只会执行 DbHelper 的 onCreate() 方法,直接建立两张表。
  • 之前已经安装过这个 App,安装时时覆盖安装。onCreate() 方法不会再执行了,只会执行 OnUpgrade() 方法。这时候就要判断老版本号是多少,然后在老版本的数据库上进行升级。

第三版的 App 又提出来一个新需求:要给 Book 表和 Category 表建立关联,要在 Book 表中添加一个 category_id 字段,代码如下

private static final int VERSION = 3;  // 版本号加 1,现在是 3

// Book 表
private static final String CREATE_TBL_BOOK = "CREATE TABLE Book ("
        + "id INTEGER PRIMARY KEY AUTOINCREMENT, "
        + "name TEXT, "
        + "author TEXT, "
        + "prices INTEGER, "
        + "pages INTEGER, "
        + "category_id INTEGER"  // 增加字段
        + ")";

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_TBL_CATEGORY)
    db.execSQL(CREATE_TBL_BOOK);  // 建立新表
}

@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");  // 增加字段
        default:
            break;
    }
}

注意:

OnUpgrade() 方法中的 switch 语句是没有 break 的,会一直执行到语句结束。为什么要这么写想想就明白了。比如用户手上的版本是 1,新版 App 的版本是 5,那么就会有 4 个版本的数据库升级,switch() 自然不能中途 break,必须执行这 4 个版本的数据库升级语句。

优点:
每次更新数据库的时候只需要在onUpgrade方法的末尾加一段从上个版本升级到新版本的代码,易于理解和维护

缺点:
当版本变多之后,多次迭代升级可能需要花费不少时间,增加用户等待时间

2、使用if判断跳跃升级:

表2.1

版本 字段1 字段2 字段3 字段4 字段5
1 ID name password
2 ID name password address
3 ID name password address subject
4 ID name password
ID subject

发现数据库3存在冗余,需要拆分数据库为4,此时只需要改变对应旧版本为3的升级操作,实现迭代升级

针对当前newVersion版本号,对每个版本的数据库进行升级操作

数据库版本1 数据库版本2 数据库版本3 newVersion
1->4 2->4 3->4 4
1->5 2->5 3->5 5

以数据库版本1、2、3为例,可以看出每次有新数据库版本时,为了保留原来数据库中的数据,这三个版本都需要进行相应的修改(红色部分)。(上面蓝色的那句话就是这种情况)

  • 增加字段

    • 使用上面其它方法的不合理之处的第一点描述的方法,也不算麻烦,在第二步新建表,不同数据库版本都使用最新的建表函数a,所以增加字段修改起来也不麻烦,只需要修改这个建表函数a即可。
  • 删除字段、或增删新表

    • 如表2.1,需要建立新表和删除字段,则数据库版本1、2、3需要进行的处理,不一样,需要分别修改。

所以这种跳跃升级不建议使用

优点:
优点:跨版本升级效率高,可以保证每个版本的用户都可以在消耗最少的时间升级到最新的数据库而无需做无用的数据多次转存

缺点:
代码维护量将越来越大,强迫开发者记忆所有版本数据库的完整结构,且每次升级时onUpgrade方法都必须全部重写

参考:
http://www.jianshu.com/p/65a025637d40
http://www.cnblogs.com/liqw/p/4264925.html
http://flyingcat2013.blog.51cto.com/7061638/1537074

关注我的公众号,轻松了解和学习更多技术
这里写图片描述

你可能感兴趣的:(Android)