新列的 SQLite 升级时列名重复

JMR*_*ies 7 sqlite android android-sqlite

当用户在更新应用程序时升级到本地 SQLite 数据库的新版本时,我遇到了不一致的、不可重现的崩溃。

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)
#################################################################
Run Code Online (Sandbox Code Playgroud)

该列是该应用程序版本的新内容,它告诉我最可能的错误是 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

看看这个,我能看到这种情况发生的唯一方法是如果 Android 调用 onUpgrade 两次,而不是调整oldVersionnewVersion参数,导致案例 7 被调用两次。相反,也可能是调用 onCreate 之后调用 onUpgrade 的情况,再次提供给方法的数据库版本不正确。

正如我在开始时提到的,我无法重现这个错误,而且它只发生在 <1% 的用户身上,但它足以让我想要解决它。如果有人有猜测,我会很感激,如果您需要更多信息,请随时询问。谢谢!

小智 6

有同样的问题。事实证明,我正在为 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" );
}
Run Code Online (Sandbox Code Playgroud)

修复方法是在创建表后检查 oldVersion 是否存在:

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

希望它对某人有帮助。