【问题标题】:SQLiteOpenHelper onUpgrade() Confusion AndroidSQLiteOpenHelper onUpgrade() 混淆Android
【发布时间】:2011-03-31 04:08:18
【问题描述】:

我正在使用数据库开发我的第一个应用程序,但我在理解 onUpgrade 函数时遇到了一些问题。我的数据库有一个表,其中包含一个项目和一个收藏列,以便用户可以收藏一个项目。我看到的大多数实现只是删除表并重建它,但我不想这样做。我希望能够向表中添加更多项目。

当应用程序通过 android 市场升级时,数据库是否知道它的版本号?那么我可以增加代码中的版本号,然后将其导出到市场,当用户第一次启动升级版本时,会调用 onUpgrade 吗?

如果是这种情况,我的 onUpgrade 会简单地从文件中提取并添加数据库项。这是一种标准的做事方式,还是在 Android 中有更好的处理方式。我尽量保持标准。

谢谢

【问题讨论】:

  • 你知道迈克,已经一年了。你真的应该接受其中一个答案
  • 上次访问时间:2010 年 9 月 7 日 17:35
  • 几年过去了,但迈克不打电话给onUpgrade()
  • 再过一年,我们到了,不接受答案!可能他只是忘记了密码!
  • 4 年不足以让迈克得到值得他接受的答案...

标签: android database sqlite


【解决方案1】:

好的,在您遇到更大的问题之前,您应该知道 SQLite 受限于 ALTER TABLE 命令,它只允许 addrename 不允许删除/删除,这是通过重新创建表来完成的。

您应该随时准备好新的表创建查询,并将其用于升级和传输任何现有数据。注意:onUpgrade 方法为您的 sqlite 助手对象运行一个方法,您需要处理其中的所有表。

那么在Upgrade上有什么推荐:

  • 开始交易
  • 使用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();
}

【讨论】:

  • 您好 Pentium,答案很好,我想知道您能否澄清一下我是如何“获得与新列的交集,这次是从升级表中获取的列”?
  • 它在代码中它是列表中的retainAll方法,所以oldColumns.retainAll(newColumns)当时DBUtils.GetColumns(db, TableName)将返回新列,因为新表刚刚创建,columns变量在重命名表之前保存对列的引用,所以旧列。
  • StringUtils.join 是不必要的。 Android 有一个 TextUtils 类,它有一个 join 方法,参见TextUtils.join。否则是一个很好的答案。
  • 我多次阅读这个答案。由于详细的解释,它总是给人一种很好的感觉。
  • 您好,感谢您的回答。快速提问:真的有必要在onUpgrade() 内部调用beginTransaction()setTransactionSuccessful() 吗?因为在SQLiteOpenHelper 中对onUpgrade() 的调用已经被这两个包围了。
【解决方案2】:

在 Pentium10 的出色答案旁边,这里有一些来自活代码的好例子:

【讨论】:

  • 遗憾的是,Google 代码搜索现已关闭,因此无法查看这些示例。
  • 刚刚用非死链接编辑了答案...感谢您的出色回答!
【解决方案3】:

感谢您澄清 onUpgrade() 将不支持删除/删除语句@Pentium 10

对于那些想知道 onUpgrade() 被调用的确切时间的人来说,它是在调用 getReadableDatabase() 或 getWriteableDatabase() 期间。

对于那些不清楚它如何确保触发的人......答案是:当提供给 SqliteOpenHelper 的构造函数的数据库版本更新时触发。这是一个例子

public class dbSchemaHelper extends SQLiteOpenHelper {

private String sql;
private final String D_TAG = "FundExpense";
//update this to get onUpgrade() method of sqliteopenhelper class called
static final int DB_VERSION = 2; 
static final String DB_NAME = "fundExpenseManager";

public dbSchemaHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
    // TODO Auto-generated constructor stub
}

现在到...onUpgrade()

@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
    sql = "ALTER TABLE " + fundExpenseSchema.Expense.TABLE_NAME + " ADD COLUMN " + fundExpenseSchema.Expense.FUNDID + " INTEGER";
    arg0.execSQL(sql);
}

【讨论】:

  • 请不要在您的帖子上签名。将您的网站放在您的个人资料中。
  • 升级 DB_VERSION 编号的用例是什么?
【解决方案4】:

我一直在使用@Pentium10提出的解决方案,但是今天我遇到了一个问题,在做alter table之后,原始表中的getColumns仍然返回相同的列(在新版本的db中表遭受市长结构变化,一些列添加了一些其他),真的我不知道为什么选择语句不反映结构变化,在再次创建我的表之前,选择语句仍然返回列!尚未重新创建表时!

所以我设法使用pragma table_info 更新 getColumns 方法来解决这个问题,如下所示:

    /**
 * Get a list of column base_dictionary for the selected table
 *
 * @param db
 *  Database that contains the table
 * @param tableName
 *  Table name to be used
 * @return A List of column name
 */
public static List<String> getColumns(SQLiteDatabase db, String tableName) {
    List<String> ar = null;
    Cursor c = null;
    try {
        c = db.rawQuery("pragma table_info(" + tableName + ")", null);

        ar = new ArrayList<String>();
        if (c != null && c.moveToFirst()) {
            do {
                ar.add(c.getString(c.getColumnIndexOrThrow("name")));
            } while (c.moveToNext());
            c.close();
        }

    } catch (Exception e) {
        Log.v(tableName, e.getMessage(), e);
        e.printStackTrace();
    } finally {
        if (c != null) c.close();
    }
    return ar;
}

【讨论】:

    猜你喜欢
    • 2014-09-21
    • 2021-11-05
    • 1970-01-01
    • 1970-01-01
    • 2018-11-04
    • 2016-09-17
    相关资源
    最近更新 更多