使用多个表升级Android应用程序数据(不破坏未受影响的表)

时间:2011-09-28 15:46:29

标签: android sqlite upgrade

在我的Android应用程序中;我有一个包含多个表的数据库。 每个表或多或少都是彼此分开的,但是想(只为最佳实践?)只有一个DB文件。

谈到升级时,它目前是一个全有或全无的事情。在升级时,它“DROP”的所有表并重新创建它们。但是,如果只有一个表发生了变化,那么这一点就相当苛刻,因为所有其他表的数据也都会丢失。

是否有内置方法可以自动升级已更改的表? (例如,使用/ table的版本号?)

如果没有,我想我可以看到两个选项:

  1. 为每个表使用单独的数据库/文件,以使用内置版本升级功能。

  2. 使用数据库版本号来了解“架构”何时发生了变化,但是有一个单独的表来存储当前的TABLE_VERSIONS并通过根据当前构建和DROP检查每个表的版本号来管理我自己的升级/根据需要创建表。

  3. (我宁愿不在这里重新发明轮子,所以我希望我能错过一些简单的......)

2 个答案:

答案 0 :(得分:1)

您需要一个抽象类来实现此处描述的升级过程。然后,为每个表扩展此抽象类。在您的抽象类中,您必须以某种方式存储表(列表,硬编码),因此当onUpgrade触发您迭代表项时,对于每个表项,您将执行所描述的步骤。它们将自我升级,保留所有现有细节。请注意,onUpgrade事件每个数据库只触发一次,这就是为什么你需要迭代所有表来进行所有表的升级。您在所有数据库中只维护了1个版本号。

  • 的BeginTransaction
  • 使用if not exists运行表创建(我们正在进行升级,因此表可能尚未存在,它将无法更改和删除)
  • 列出现有列List<String> columns = DBUtils.GetColumns(db, TableName);
  • 备用表(ALTER table " + TableName + " RENAME TO 'temp_" + TableName
  • 创建新表(最新的表创建架构)
  • 获取与新列的交集,这次是从升级后的表格中取得的列(columns.retainAll(DBUtils.GetColumns(db, TableName));
  • 恢复数据(String cols = StringUtils.join(columns, ","); db.execSQL(String.format( "INSERT INTO %s (%s) SELECT %s from temp_%s", TableName, cols, cols, TableName));
  • 删除备用表(DROP table 'temp_" + TableName
  • setTransactionSuccessful

(这不会处理表降级,如果重命名列,则不会因列名不匹配而传输现有数据。)

public static List<String> GetColumns(SQLiteDatabase db, String tableName) {
    List<String> ar = null;
    Cursor c = null;
    try {
        c = db.rawQuery("select * from " + tableName + " limit 1", null);
        if (c != null) {
            ar = new ArrayList<String>(Arrays.asList(c.getColumnNames()));
        }
    } catch (Exception e) {
        Log.v(tableName, e.getMessage(), e);
        e.printStackTrace();
    } finally {
        if (c != null)
            c.close();
    }
    return ar;
}

public static String join(List<String> list, String delim) {
    StringBuilder buf = new StringBuilder();
    int num = list.size();
    for (int i = 0; i < num; i++) {
        if (i != 0)
            buf.append(delim);
        buf.append((String) list.get(i));
    }
    return buf.toString();
} 

答案 1 :(得分:1)

如果您正在使用Android SQLite帮助程序类(即SQLiteOpenHelper),那么您只有一个代表数据库架构的版本号。就个人而言,我将所有架构创建代码放在SQLiteOpenHelper的实例中,并保持升级逻辑简单:

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

    // Alter all the tables so the schema is brought up-to-date.
    if (oldVersion < newVersion) {
        db.execSQL("ALTER TABLE foo ADD COLUMN new_column INTEGER NOT NULL");
    }
}