用户在更新应用程序时升级到本地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,并且没有调整
oldVersion
和newVersion
参数,则导致情况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" );
}
希望它对某人有帮助。