您的位置:首页 > 其它

一个困惑引起的思考

2014-10-09 15:40 465 查看


预备

Android提供了SQLiteOpenHelper用于简化数据库管理。其中两个重要api:

onCreate, Called when the database is created for the first time. This is where the creation of tables and the initial population of the tables should happen.
onUpgrade, Called when the database needs to be upgraded. The implementation should use this method to drop tables, add tables, or do anything else it needs to upgrade to the new schema version.


开始

onUpgrade的话题,话题来子文首的博客地址。 话题涉及数据库的3个版本, V1时有一个表news,V2时新添加了一个表comment,V3时给comment表添加了个字段publishdate。 我直接提V1 V2 V3的代码吧,并在最后小结下。
// V1
public class MySQLiteHelper extends SQLiteOpenHelper {
public static final int VERSION = 1;
// V1
public static final String CREATE_NEWS_V1 = "create table news ("
+ "id integer primary key autoincrement, "
+ "title text, "
+ "content text, "
+ "publishdate integer,"
+ "commentcount integer)";

// // V2
// public static final String CREATE_COMMENT_V2 = "create table comment ("
// + "id integer primary key autoincrement, "
// + "content text)";
//
// // V3
// public static final String CREATE_COMMENT_V3 = "create table comment ("
// + "id integer primary key autoincrement, "
// + "content text, "
// + "publishdate integer)";

public MySQLiteHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_NEWS_V1);
// // V2 add
// db.execSQL(CREATE_COMMENT_V2);
// V3 add
// db.execSQL(CREATE_COMMENT_V3);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// switch (oldVersion) {
// case 1: // V2 add
// db.execSQL(CREATE_COMMENT_V2);
// case 2: // V3 add
// db.execSQL("alter table comment add column publishdate integer");
// default:
// }
}

}

// V2
public class MySQLiteHelper extends SQLiteOpenHelper {
public static final int VERSION = 2;
// V1
public static final String CREATE_NEWS_V1 = "create table news ("
+ "id integer primary key autoincrement, "
+ "title text, "
+ "content text, "
+ "publishdate integer,"
+ "commentcount integer)";

// V2
public static final String CREATE_COMMENT_V2 = "create table comment ("
+ "id integer primary key autoincrement, "
+ "content text)";

//
// // V3
// public static final String CREATE_COMMENT_V3 = "create table comment ("
// + "id integer primary key autoincrement, "
// + "content text, "
// + "publishdate integer)";

public MySQLiteHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_NEWS_V1);
// V2 add
db.execSQL(CREATE_COMMENT_V2);
// V3 add
// db.execSQL(CREATE_COMMENT_V3);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1: // V2 add
db.execSQL(CREATE_COMMENT_V2);
// case 2: // V3 add
// db.execSQL("alter table comment add column publishdate integer");
default:
}
}

}

// V3
public class MySQLiteHelper extends SQLiteOpenHelper {
public static final int VERSION = 3;
// V1
public static final String CREATE_NEWS_V1 = "create table news ("
+ "id integer primary key autoincrement, "
+ "title text, "
+ "content text, "
+ "publishdate integer,"
+ "commentcount integer)";

// V2
public static final String CREATE_COMMENT_V2 = "create table comment ("
+ "id integer primary key autoincrement, "
+ "content text)";

// V3
public static final String CREATE_COMMENT_V3 = "create table comment ("
+ "id integer primary key autoincrement, "
+ "content text, "
+ "publishdate integer)";

public MySQLiteHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_NEWS_V1);
// // V2 add
// db.execSQL(CREATE_COMMENT_V2);
// V3 add
db.execSQL(CREATE_COMMENT_V3);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1: // V2 add
db.execSQL(CREATE_COMMENT_V2);
case 2: // V3 add
db.execSQL("alter table comment add column publishdate integer");
default:
}
}

}


经过验证V1升级到V2, V2升级到V3 或者V1直接升级到V3均测试ok. 小结:

onCreate中创建的语句始终要用最新版本的。因为系统调用了SQLiteOpenHelper的onCreate说明是初次创建数据库,当然得创建最新的表结构。
onUpgrade方法中, switch case结构如果选择fall through(不要break等跳转)的话,就要针对不同oldVersion的case写出合理的更新语句。在代码V2中upgrade是新增表,在代码V3中要在V2的基础上修改表来添加字段。switch case要break的话见文首博客里。(其实onUpgrade方法实现也简单,只要合理抽出各个版本见的的差异,逐个应用就ok)。
最初用博文中的代码从V1升级到V3会异常的根源就在于没很好的区分逐个版本升级的delt差异。
很多常见的升级方式是在onUpgrade中直接drop之前的表再手动调用onCreate来创建,这样的话老数据就丢失了。
为了相对减少数据库升级该怎么作好呢,1.可以前期充分分析尽量减少不必要的后期改动。2.则是给数据库预留写字段备用,像android contact里面很多field1 field2 field3等。
总有其他办法。。。

fork the code,

https://github.com/cheyiliu/test4android/tree/master/src/test/db/upgrade

ref

http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html
/article/1645817.html
/article/1358119.html


补充

SQLite对ALTER TABLE的支持是有限的,你可以在一个存在表上添加一个字段到末尾,或者是改变表的名称。但如果你想做更复杂的操作,比如删除一个表已有的字段,就要重新创建这个表并完成数据迁移,而不能使用DROP COLUMN这样方便的命令了。详见SQLite Frequently Questions 比如表pedant原来有三个字段a、b、c,现在想删除c字段,那么在onUpgrade中写法如下:
MyDBHelper.java
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//旧数据库版本为1,删除表pedant的c字段
if(oldVersion < 2) {
db.beginTransaction();
try {
db.execSQL("CREATE TEMPORARY TABLE pe_backup (a, b);");
db.execSQL("INSERT INTO pe_backup SELECT a, b FROM pedant;");
db.execSQL("DROP TABLE pedant;");
db.execSQL("CREATE TABLE pedant(a text, b text);");
db.execSQL("INSERT INTO pedant SELECT a, b FROM pe_backup;");
db.execSQL("DROP TABLE pe_backup;");
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
}


这样就既完成了对c字段的删除也保留了原来表上的数据。 (from:http://www.pedant.cn/2014/08/01/sqliteopenhelper-onupgrade-ondowngrade-handle/)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: