数据库 简介 升级 SQLite 总结
目录
SQLite 数据库升级
两个核心方法
当我们创建 SQLiteOpenHelper 对象的时候,如果传入的版本号大于之前的版本号,onUpgrade 方法就会被调用,通过判断 oldVersion 和 newVersion 就可以决定如何升级数据库。升级完成后,数据库会自动存储最新的版本号为当前数据库版本号。
public class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
//在第一次打开数据库的时候才会走,清除数据后再次运行也会走
//数据库升级的时候不会走
@Override
public void onCreate(SQLiteDatabase db) {
}
//只有当数据库已经存在,而且版本升高的时候,才会走(即:数据库升级的时候才会走)
//第一次创建数据库的时候不会走,清除数据后再次运行也不会走
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
基本思想
当数据库多次升级后,你就无法保证用户是从哪个数据库版本升上来的,此时处理的方法一般为:使用不带break的switch语句
迭代升级。
- 优点:每次更新数据库的时候只需要在 onUpgrade 方法的末尾加一段从上个版本升级到新版本的代码,易于理解和维护
- 缺点:当版本变多之后,多次迭代升级可能比较费时
另一种方式是,使用if判断,针对当前 newVersion 版本号,对每个版本的数据库进行升级操作
- 优点:跨版本升级
效率
高,可以保证每个版本的用户都可以在消耗最少的时间
升级到最新的数据库而无需做无用的数据多次转存 - 缺点:代码维护量将越来越大,强迫开发者记忆所有版本数据库的完整结构,且每次升级时 onUpgrade 方法都必须全部重写
- 结论:这种跳跃升级不建议使用
ALTER 命令的局限性
SQLite supports a limited subset of ALTER TABLE. The ALTER TABLE command in SQLite allows the user to rename a table or to add a new column to an existing table. It is not possible to rename a column, remove a column, or add or remove constraints from a table.
SQLite 支持 ALTER TABLE 的有限子集。SQLite 中的 ALTER TABLE 命令允许用户重命名表或向现有表添加新列(并且只能在表的末尾添加新列)。无法重命名列,删除列,或从表中添加或删除约束。
如果真的需要重命名列或删除列,只能通过下面的方式间接实现:
- 将表名改成临时表:
ALTER TABLE Order RENAME TO _Order;
- 创建新表:
CREATE TABLE Order(...);
- 导入数据:
INSERTINTO Order SELECT id, “”, Age FROM _Order;
- 删除临时表:
DROP TABLE _Order;
数据库迁移
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
//注意,这里的 switch 语句是没有 break 的,会一直执行到语句结束
case 1:
db.execSQL(CREATE_TBL_CATEGORY) // 建立新表
case 2:
db.execSQL("ALTER TABLE Book ADD COLUMN category_id INTEGER"); // 增加新列(字段)
//注意每次的 case 中添加的创建新表的sql代码不要忘了在 onCreate 中同时添加,因为新用户也是要执行的
case 3:
//删除列,或者更改一个已经存在的字段的名称、数据类型、限定符等,需要建立新表,并将原表的数据复制到新表中
db.beginTransaction();
db.execSQL("alter table book rename to _temp_book"); //旧的表先修改为一个临时名
db.execSQL("create table book(bookId integer primarykey, bookName text);"); //重新创建一个新的表
db.execSQL("insert into book select *,'' from _temp_book"); //同步旧的数据到新的表
db.execSQL("drop table _temp_book"); //删除旧的表
db.setTransactionSuccessful();
db.endTransaction();
default:
break;
}
}
案例
第一版需求
有个图书管理相关的 App,有一张图书表 —— Book,其表结构如下
字段名 | 类型 | 说明 |
---|---|---|
id | INTEGER | 主键 |
name | TEXT | 书名 |
author | TEXT | 作者 |
price | INTEGER | 价格 |
pages | INTEGER | 页数 |
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) {
super(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TBL_BOOK); //创建表1
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
第二版需求
几个星期之后,第二版的需求来了,需要增加一个书籍分类表 —— Category,其表结构如下:
字段名 | 类型 | 说明 |
---|---|---|
id | INTEGER | 主键 |
category_name | TEXT | 分类名称 |
category_code | INTEGER | 分类代码 |
这个时候,就需要对数据库进行升级,增加一张表。
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_BOOK); // 建立表1
db.execSQL(CREATE_TBL_CATEGORY) // 建立表2
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL(CREATE_TBL_CATEGORY) // 建立表2
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_BOOK); // 直接建立最新的表1
db.execSQL(CREATE_TBL_CATEGORY) // 建立表2
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL(CREATE_TBL_CATEGORY) // 建立新表2
case 2:
db.execSQL("ALTER TABLE Book ADD COLUMN category_id INTEGER"); // 修改表1,增加字段
default:
break;
}
}
2019-2-27
本文来自博客园,作者:白乾涛,转载请注明原文链接:https://www.cnblogs.com/baiqiantao/p/10444800.html