用户在更新应用程序时升级到本地SQLite DB的新版本时,出现了不一致,不可重现的崩溃。

Fatal Exception: android.database.sqlite.SQLiteException: duplicate column name: upload_pending (code 1): , while compiling: ALTER TABLE purchases ADD COLUMN upload_pending TINYINT DEFAULT 0
#################################################################
Error Code : 1 (SQLITE_ERROR)
Caused By : SQL(query) error or missing database.
    (duplicate column name: upload_pending (code 1): , while compiling: ALTER TABLE purchases ADD COLUMN upload_pending TINYINT DEFAULT 0)
#################################################################

该列是该版本应用程序的新增内容,它告诉我最可能的错误是SQLiteOpenHelper的onUpgrade方法被调用了两次。这是处理升级的逻辑:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    for(int currentUpgrade = oldVersion + 1; currentUpgrade <= newVersion; currentUpgrade++) {
        switch(currentUpgrade) {
            case 2:
                //upgrade to db v2
                break;
            case 3:
                //upgrade to db v3
                break;
            //etc
            case 7:
                methodWhichUpdatesAnotherTable(db);
                db.execSQL("ALTER TABLE " + Purchases.TABLE_NAME
                            + " ADD COLUMN " + Purchases.UPLOAD_PENDING + " TINYINT DEFAULT 0");
                break;
        }
    }
}

编辑:我更新了代码,以包括一些重要的内容。失败的行不是升级中的第一个ALTER语句。首先,调用一个使两个不同的alter语句(在不同的表上)的方法,该部分可以正常工作。这似乎消除了并发问题的可能性,因为如果是这样,这些将是第一个失败的对象。

对此,我可以看到的唯一方法是,如果Android两次调用onUpgrade,并且没有调整oldVersionnewVersion参数,则导致情况7被调用了两次。相反,可能是在调用onCreate并随后调用onUpgrade的情况下,再次提供给该方法的数据库版本不正确。

正如我在开始时提到的那样,我无法重现此错误,并且仅在不到1%的用户中发生,但是对于我来说,解决它已经足够明显了。如果有人有猜测,我将不胜感激,如果您需要更多信息,请随时提问。谢谢!

最佳答案

有同样的问题。原来,我正在为4之前的oldVersions创建表,并为10之前的版本添加列。因此,对于4之前的oldVersions执行了两个语句CREATE TABLE和ALTER TABLE ADD COLUMN:

if ( oldVersion < 4 && newVersion >= 4 ) {
    TestTableDao.createTable( db, true );
}

if ( oldVersion < 10 && newVersion >= 10 ) {
   db.execSQL( "ALTER TABLE TEXT_TABLE ADD COLUMN NEW_COLUMN TEXT" );
}

解决方法是在创建表后检查oldVersion是否存在:
 if ( oldVersion < 10 && newVersion >= 10 ) {
   if( oldVersion >=4 )
       db.execSQL( "ALTER TABLE TEXT_TABLE ADD COLUMN NEW_COLUMN TEXT" );
}

希望它对某人有帮助。

10-07 19:25
查看更多