SQLite OnUpgrade数据迁移失败:execSQL可能不会丢弃表

时间:2016-02-19 04:36:12

标签: android sqlite

我的应用程序中有一个SQLite数据库,我正在尝试将其从版本4迁移到版本5.如果我卸载然后重新安装,则应用程序正常工作。为了便于理解,我将恢复这个问题。

在v4中我创建了这个表:

private static final String CREATE_TABLE = "CREATE TABLE " + Globals._TABLE +
        " ( " +
        Globals._ID + " INTEGER PRIMARY KEY, " +
        Globals._PRIORITY + " INTEGER, " +
        Globals._FUNC_NAME + " TEXT " +
        ");";

在第5版中,我删除了_PRIORITY和_FUNC_NAME列。我还使用MySQL DB提供的索引编制索引。我需要创建一种在内部索引DB的方法。所以我创建了这样的表:

private static final String CREATE_TABLE =
        "CREATE TABLE IF NOT EXISTS " + Globals._TABLE +
                " ( " +
                Globals._SQLITE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                Globals._UPLOADED + " INTEGER, " +
                Globals._ID + " INTEGER DEFAULT 0 " +
                ");";

我的OnCreate方法就是这样,并没有抛出任何错误:

@Override
public void onCreate( SQLiteDatabase db )
{
    try
    {
        db.execSQL( CREATE_TABLE );
    }
    catch( SQLException e )
    {
        e.printStackTrace( );
    }
}

我正在使用此查询删除表:

    private static final String DROP_TABLE = "DROP TABLE IF EXISTS " + Globals._TABLE;

我的OnUpgrade方法就是这样,也不会抛出错误:

SQLiteMigratorV5 migrator = new SQLiteMigratorV5( mContext, db );

    switch( newVersion )
    {
        case 5:
            migrator.saveData( );
            break;
        default:
            break;
    }

    try
    {
        db.execSQL( DROP_TABLE );
    }
    catch( SQLException e )
    {
        e.printStackTrace( );
    }

    onCreate( db );

    switch( newVersion )
    {
        case 5:
            migrator.restoreData( );
            break;
        default:
            break;
    }
}

调试应用程序我可以看到onUpgrade和OnCreate都被调用。我的负责迁移的类保存了所有数据,并且应该将所有数据恢复到新表中。调试我也可以说旧表中的所有行都正确地插入到新表中。

当我尝试访问此数据时会出现问题。我有另一个表,通过id索引第一个表中的元素,我还重新创建了另一个表,我需要使用SQLite id进行索引。所以我正在执行rawQuery并检索游标:

String query = "SELECT * FROM " + Globals._TABLE + " WHERE " + Globals._ID + " = '1'";
Cursor cursor = mDB.rawQuery( query, null );

当我检查游标列时,我找不到_SQLITE_ID既没有_​​UPLOADED但是我可以找到_PRIORITY和_FUNC_NAME,当我尝试在我的另一个表中使用新插入的行_SQLITE_ID时,这会导致我出错。

for( cursor.moveToFirst( ); ! cursor.isAfterLast( ); cursor.moveToNext( ) )
{
    setSQLiteId( cursor.getInt( cursor.getColumnIndex( Globals._SQLITE_ID ) ) ); 
    ...
}

这段代码引出了我的错误:

java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.

我不止一次检查了所有内容,我无法理解发生了什么,我唯一的假设是旧表没有被删除而新的表没有被创建因为CREATE TABLE IF不存在

任何人都可以告诉我如何解决这个问题?

好的,我解决了这个问题,但我仍然没有解释

我的onUpgrade以这种方式调用:storesData>删除表>创建表格>恢复数据。

在我的商店功能中,我有这个功能:

public List< Client > getClientsWhereV4( String statement )
{
    if( statement == null )
    {
        statement = "";
    }

    String query = "SELECT * FROM " + Globals._TABLE + " " + statement;

    Cursor cursor = mDB.rawQuery( query, null );

    List< Client > clientList = new ArrayList<>( );
    for( cursor.moveToFirst( ); ! cursor.isAfterLast( ); cursor.moveToNext( ) )
    {
        Client client = new Client( mContext );

        // Already ignoring deleted columns
        client.setId( cursor.getInt( cursor.getColumnIndex( Globals._ID ) ) );

        clientList.add( client );
    }
    cursor.close( );

    return clientList;
}

这是我的恢复功能:

public List< Client > getClientsWhereV5( String statement )
{
    if( statement == null )
    {
        statement = "";
    }

    String query = "SELECT * FROM " + Globals._TABLE + " " + statement;

    Cursor cursor = mDB.rawQuery( query, null );

    List< Client > clientList = new ArrayList<>( );
    for( cursor.moveToFirst( ); ! cursor.isAfterLast( ); cursor.moveToNext( ) )
    {
        Client client = new Client();

        setSQLiteId( cursor.getInt( cursor.getColumnIndex( Globals.CLIENT_SQLITE_ID ) ) );
        if( cursor.getInt( cursor.getColumnIndex( Globals.CLIENT_UPLOADED ) ) == 1 )
        {
            setUploaded( true );
        }
        else
        {
            setUploaded( false );
        }
        setId( cursor.getInt( cursor.getColumnIndex( Globals.CLIENT_ID ) ) );

        clientList.add( client );
    }
    cursor.close( );

    return clientList;
}

如果商店查询等于还原查询,则会发生错误,例如:

// v4    
String query = "SELECT * FROM " + Globals._TABLE + " " + statement;
// v5
String query = "SELECT * FROM " + Globals._TABLE + " " + statement;

如果有任何差异,一个人有一个空间或类似的东西,它可以正常工作。所有变量都是函数的局部变量,我关闭了游标,我不知道发生了什么。

2 个答案:

答案 0 :(得分:0)

我认为错误是由于光标的位置,

尝试使用cursor.moveToFirst()首先将光标移动到返回数据的第一行:

if (cursor.moveToFirst()) {
    // Do your data access here, 
    // like cursor.getInt(...)
}

希望这有帮助。

答案 1 :(得分:-1)

尝试一些类似的事情。它应该有帮助

while(cursor.moveToNext){
//do something.
// access your data from table here.
}