27

假设我在 SQLiteOpenHelper 中有一个包含 2 列的数据库表 test_table 和相应的创建脚本:

DB_VERSION = 1:
public void onCreate(SQLiteDatabase db)
{
db.execSql("CREATE table test_table (COL_A, COL_B);
}

这是在 Play 商店中发布的初始应用程序版本 1。

一段时间后,应用程序和使用的数据库会更新。我猜 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 语句?

我问是因为在我的应用程序中,用户可以导出和导入数据,这无非是导出:复制整个数据库并导入:将应用程序数据库替换为备份副本数据库。

如果用户拥有应用程序版本 1,导出数据库,升级应用程序(新数据库结构)并导入旧版本 1 备份,会发生什么情况?--> SQLiteOpenHelper 将如何表现?--> 处理数据库升级和导入/导出功能的正确方法是什么?

4

4 回答 4

34

处理实时应用程序的数据库升级的正确方法是什么,以便用户不会丢失他的数据?您是否必须在 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 备份,会发生什么情况?--> SQLiteOpenHelper 将如何表现?

如果通过“复制整个数据库”,您的字面意思是 SQLite 数据库文件的完整文件副本,那么当SQLiteOpenHelper打开恢复的备份时,数据库将具有旧的模式版本并且将onUpgrade()正常通过。

处理数据库升级和导入/导出功能的正确方法是什么?

我怀疑答案是:要么通过复制整个文件来进行备份,要么还安排备份和恢复模式版本,你可以通过调用getVersion()一个SQLiteDatabase对象来获得它。话虽如此,我还没有过多地处理这种情况,并且可能还有更多我没有想到的问题。

于 2013-01-19T22:36:39.413 回答
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 的升级逻辑

继续为每个新的数据库版本升级添加新案例,这将进行增量更改

于 2014-11-14T12:02:32.987 回答
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;");"
    }

这样您就不必担心数据丢失或增量更改

于 2015-11-02T05:56:25.933 回答
1

我认为回答这个问题为时已晚,但它可能对其他人有所帮助。

     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

这样就不会混淆数据库版本。

于 2018-02-04T00:18:18.923 回答