让我们假设我在SQLiteOpenHelper中有一个包含2列的数据库表test_table和相应的创建脚本:
DB_VERSION = 1:
public void onCreate(SQLiteDatabase db)
{
db.execSql("CREATE table test_table (COL_A, COL_B);
}
这是初始应用版本1,已在Play商店中发布。
过了一段时间,应用程序和使用的数据库都有更新。 我想SQLiteOpenHelper类必须像这样调整:
DB_VERSION = 2:
public void onCreate(SQLiteDatabase db)
{
db.execSql("CREATE table test_table (COL_A, COL_B, COL_C)");
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSql("ALTER TABLE test_table ADD Column COL_C");
}
一段时间后,另一个应用更新:
DB_VERSION = 3:
public void onCreate(SQLiteDatabase db)
{
db.execSql("CREATE table test_table (COL_A, COL_B, COL_C, COL_D)");
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSql("ALTER TABLE test_table ADD Column COL_D");
}
- >这是我需要建议的地方。 如果用户安装应用版本1,则他有列A和B. 如果他随后更新到版本2,则onUpgrade将触发并添加列C. 从头开始安装的新用户通过create语句获取3列。 如果用户随后更新到版本3,则onUpgrade再次触发并添加列D. 但是,如果用户安装应用版本1,那么跳过版本2的更新并更新版本3?那他就错过了
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSql("ALTER TABLE test_table ADD Column COL_C");
}
部分且仅
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSql("ALTER TABLE test_table ADD Column COL_D");
}
会调用,这会导致表test_table(COL_A,COL_B,COL_D)??
处理实时应用的数据库升级的正确方法是什么,因此用户不会丢失数据? 您是否必须在onUpgrade()方法中检查所有可能的(旧)版本,并根据该版本执行不同的alter table语句?
我问,因为在我的应用程序中,用户可以导出和导入数据,这只不过是导出:复制整个数据库并导入:用备份副本数据库替换app数据库。
如果用户拥有应用版本1,导出数据库,升级应用(新数据库结构)并导入旧版本1备份,会发生什么? - > SQLiteOpenHelper将如何表现? - >处理数据库升级和导入/导出功能的正确方法是什么?
答案 0 :(得分:33)
处理实时应用的数据库升级的正确方法是什么,因此用户不会丢失数据?您是否必须在onUpgrade()方法中检查所有可能的(旧)版本,并根据该版本执行不同的alter table语句?
总的来说,是的。
一种常见的方法是进行成对升级:
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion<2) {
// do upgrade from 1 to 2
}
if (oldVersion<3) {
// do upgrade from 2 to 3, which will also cover 1->3,
// since you just upgraded 1->2
}
// and so on
}
这大致相当于Rails迁移,例如。
如果用户拥有应用版本1,导出数据库,升级应用(新数据库结构)并导入旧版本1备份,会发生什么? - &GT; SQLiteOpenHelper将如何表现?
如果通过“复制整个数据库”,你的字面意思是SQLite数据库文件的完整文件副本,那么当SQLiteOpenHelper
打开还原的备份时,数据库将具有旧的模式版本并将照常进行onUpgrade()
。
使用导入/导出功能处理数据库升级的正确方法是什么?
我怀疑答案是:通过复制整个文件来进行备份,或者还安排备份和恢复架构版本,您可以通过调用getVersion()
对象上的SQLiteDatabase
来获取该版本。话虽如此,我还没有多少处理这个场景,可能还有更多我没想到的问题。
答案 1 :(得分:19)
以下伪代码显示增量升级
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch(oldVersion) {
case 2:
//upgrade logic from version 2 to 3
case 3:
//upgrade logic from version 3 to 4
case 4:
//upgrade logic from version 4 to 5
break;
default:
throw new IllegalStateException(
"onUpgrade() with unknown oldVersion" + oldVersion));
}
}
通过增量升级我的意思是 - 注意案例2和3中缺少的break语句
如果旧版本为2且新版本为4,那么逻辑将数据库从2升级到3再升级到4
如果旧版本为3且新版本为4,则它将仅运行3到4的升级逻辑
不断为每个新的数据库版本升级添加新案例,以进行增量更改
答案 2 :(得分:3)
我怀疑你也可以用你需要的所有列创建一个新表
CREATE TABLE new_test_table (COL_A, COL_B, COL_C,COL_D);
将旧表中的数据复制到新的
INSERT INTO new_test_table SELECT * FROM test_table;
放下旧桌子
DROP TABLE test_table;
并重命名新表
ALTER TABLE new_test_table
RENAME TO test_table;
所以简而言之
public void onUpgrade(SQLiteDatabase db,int OldVersion,int NewVersion){
db.execSQL("CREATE TABLE new_test_table (COL_A, COL_B, COL_C,COL_D);"+
"INSERT INTO new_test_table SELECT * FROM test_table;"+
"DROP TABLE test_table;"+
"ALTER TABLE new_test_table RENAME TO test_table;");"
}
这样您就不必担心数据删除或增量更改
答案 3 :(得分:0)
我认为回答这个问题为时已晚,但可能有助于其他人。
DB_VERSION = 1:
public void onCreate(SQLiteDatabase db)
{
db.execSql("CREATE table test_table (COL_A, COL_B, COL_C, COL_D, COL_E);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
switch (oldVersion) {
case 1: db.execSql("ALTER TABLE test_table ADD Column COL_C");
db.execSql("ALTER TABLE test_table ADD Column COL_D");
db.execSql("ALTER TABLE test_table ADD Column COL_E");
break;
case 2: db.execSql("ALTER TABLE test_table ADD Column COL_D");
db.execSql("ALTER TABLE test_table ADD Column COL_E");
break;
case 3: db.execSql("ALTER TABLE test_table ADD Column COL_E");
break;
and so on...
}
如果用户第一次安装应用,他将从 onCreate
获取所有列如果旧版本的数据库2,则案例2添加C和D列。
如果旧版本的数据库3,则案例3仅添加列E
通过这种方式,数据库版本没有混淆。