【问题标题】:android room database returns wrong schema tableandroid 房间数据库返回错误的模式表
【发布时间】:2019-12-09 17:13:58
【问题描述】:

我有一个数据库迁移问题

使用:Kotlin,房间

我想将数据库从 1 升级到 3
我已经成功地完成了从 1 到 2 和从 2 到 3 的迁移。

但是,当我尝试从 1 升级到 3 时,查询的 3 迁移结果返回版本 1 的架构。

版本 1:
帐户表
列:地址、类型、id、备忘录

第 2 版:
帐户表
列:地址、类型、路径、备忘

第 3 版:
帐户表
列:地址、类型、路径、备注、订单

private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
    database.beginTransaction()

    try {
    database.execSQL("""
            CREATE TABLE Account_tmp (
            address TEXT NOT NULL, type TEXT, path TEXT, memo TEXT, 
            PRIMARY KEY(address))""")

        database.query("SELECT * FROM Account").use { cursor ->
            if (cursor != null && cursor.count > 0) {
                while (cursor.moveToNext()) {
                    val address = cursor.getString(cursor.getColumnIndex("address"))
                    val type = cursor.getString(cursor.getColumnIndex("type"))
                    val path = "Id:" + cursor.getInt(cursor.getColumnIndex("id"))
                    val memo = cursor.getInt(cursor.getColumnIndex("memo"))

                    val values = ContentValues()
                    values.put("address", address)
                    values.put("type", type)
                    values.put("path", path)
                    values.put("memo", memo)
                    database.insert("Account_tmp", SQLiteDatabase.CONFLICT_FAIL, values)
                }
            }
        }
        database.execSQL("DROP TABLE IF EXISTS Account")
        database.execSQL("ALTER TABLE Account_tmp RENAME TO Account")

        database.setTransactionSuccessful()
    } finally {
        database.endTransaction()
    }
}


private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
    database.beginTransaction()

    try {
    database.execSQL("""
            CREATE TABLE Account_tmp (
            address TEXT NOT NULL, type TEXT, path TEXT, memo TEXT, order TEXT,
            PRIMARY KEY(address))""")

        database.query("SELECT * FROM Account").use { cursor ->
            if (cursor != null && cursor.count > 0) {
                while (cursor.moveToNext()) {
                    val address = cursor.getString(cursor.getColumnIndex("address"))
                    val type = cursor.getString(cursor.getColumnIndex("type"))
                    val path = cursor.getString(cursor.getColumnIndex("path")) ************************  // getting error -> because table hasn't path column
                    val memo = cursor.getInt(cursor.getColumnIndex("memo"))

                    val values = ContentValues()
                    values.put("address", address)
                    values.put("type", type)
                    values.put("path", path)
                    values.put("memo", memo)
                    database.insert("Account_tmp", SQLiteDatabase.CONFLICT_FAIL, values)
                }
            }
        }
        database.execSQL("DROP TABLE IF EXISTS Account")
        database.execSQL("ALTER TABLE Account_tmp RENAME TO Account")

        database.setTransactionSuccessful()
    } finally {
        database.endTransaction()
    }
}

当我尝试将 db 从 1 升级到 3 时,MIGRATION_2_3 中发生异常
而且我在调试的时候,查询结果很尴尬....

private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
    database.beginTransaction()

    try {
    database.execSQL("""
            CREATE TABLE Account_tmp (
            address TEXT NOT NULL, type TEXT, path TEXT, memo TEXT, 
            PRIMARY KEY(address))""")

        database.query("SELECT * FROM Account").use { cursor ->
            if (cursor != null && cursor.count > 0) {
                while (cursor.moveToNext()) {
                    val address = cursor.getString(cursor.getColumnIndex("address"))
                    val type = cursor.getString(cursor.getColumnIndex("type"))
                    val path = "Id:" + cursor.getInt(cursor.getColumnIndex("id"))
                    val memo = cursor.getInt(cursor.getColumnIndex("memo"))

                    val values = ContentValues()
                    values.put("address", address)
                    values.put("type", type)
                    values.put("path", path)
                    values.put("memo", memo)
                    database.insert("Account_tmp", SQLiteDatabase.CONFLICT_FAIL, values)
                }
            }
        }
        database.execSQL("DROP TABLE IF EXISTS Account")
        database.execSQL("ALTER TABLE Account_tmp RENAME TO Account")

        database.setTransactionSuccessful()
    } finally {
        database.endTransaction()

        // database.query("SELECT * FROM Account") have {address, type, id, memo} (ver 1 schema) ****** -> why??
    }
}
private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
    database.beginTransaction()

    try {
    database.execSQL("""
            CREATE TABLE Account_tmp (
            address TEXT NOT NULL, type TEXT, path TEXT, memo TEXT, order TEXT,
            PRIMARY KEY(address))""")

        database.query("SELECT * FROM Account").use { cursor ->
            if (cursor != null && cursor.count > 0) {
                while (cursor.moveToNext()) {
                    // cursor's column has {address, type, id, memo} (ver 1 schema), not (address, type, path, memo)(ver 2 schema) -> why??
                    val address = cursor.getString(cursor.getColumnIndex("address"))
                    val type = cursor.getString(cursor.getColumnIndex("type"))
                    val path = cursor.getString(cursor.getColumnIndex("path")) // exception because account table has not path.. still has id column
                    val memo = cursor.getInt(cursor.getColumnIndex("memo"))

                    val values = ContentValues()
                    values.put("address", address)
                    values.put("type", type)
                    values.put("path", path)
                    values.put("memo", memo)
                    database.insert("Account_tmp", SQLiteDatabase.CONFLICT_FAIL, values)
                }
            }
        }
        database.execSQL("DROP TABLE IF EXISTS Account")
        database.execSQL("ALTER TABLE Account_tmp RENAME TO Account")

        database.setTransactionSuccessful()
    } finally {
        database.endTransaction()
    }
}

我不明白为什么 database.query("SELECT * FROM Account") 返回错误的数据库架构............

甚至,如果我在 rename to query 下面添加无意义的查询,那么我可以成功从 1 版本迁移到 3 版本

private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
    database.beginTransaction()

    try {
    database.execSQL("""
            CREATE TABLE Account_tmp (
            address TEXT NOT NULL, type TEXT, path TEXT, memo TEXT, 
            PRIMARY KEY(address))""")

        database.query("SELECT * FROM Account").use { cursor ->
            if (cursor != null && cursor.count > 0) {
                while (cursor.moveToNext()) {
                    val address = cursor.getString(cursor.getColumnIndex("address"))
                    val type = cursor.getString(cursor.getColumnIndex("type"))
                    val path = "Id:" + cursor.getInt(cursor.getColumnIndex("id"))
                    val memo = cursor.getInt(cursor.getColumnIndex("memo"))

                    val values = ContentValues()
                    values.put("address", address)
                    values.put("type", type)
                    values.put("path", path)
                    values.put("memo", memo)
                    database.insert("Account_tmp", SQLiteDatabase.CONFLICT_FAIL, values)
                }
            }
        }
        database.execSQL("DROP TABLE IF EXISTS Account")
        database.execSQL("ALTER TABLE Account_tmp RENAME TO Account")

        database.query("SELECT * FROM Account").use { cursor ->
                 Log.e(TAG, "MIGRATION_1_2, account size=${cursor.count}")
                 // If I add this code, Migration from 1 to 3 success!!!!
        }


        database.setTransactionSuccessful()
    } finally {
        database.endTransaction()
    }
}

为什么??????????????????
我想知道为什么!!!!

请帮帮我
这是我的数据库代码

companion object {

    private const val TAG = "TestDatabase"

    @Volatile
    private var instance: TestDatabase? = null

    fun getInstance(context: Context): TestDatabase =
            instance ?: synchronized(this) {
                instance
                        ?: buildDatabase(context).also { instance = it }
            }

    private fun buildDatabase(context: Context) =
            Room.databaseBuilder(context, TestDatabase::class.java, "test_database.db")
                    .allowMainThreadQueries()
                    .addMigrations(MIGRATION_1_2)
                    .addMigrations(MIGRATION_2_3)
                    .build()

    private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
        ...
    }
    private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
        ...
    }
}

【问题讨论】:

    标签: android database sqlite kotlin


    【解决方案1】:

    我认为您的问题是您使用了关键字,即 order 来表示 MIGRATION_2_3 中添加的列名。

    日志将包含类似于以下内容的内容:-

    2019-12-10 20:55:51.508 27554-27554/a.so59253634migrationschemanotchanging E/AndroidRuntime: FATAL EXCEPTION: main
        Process: a.so59253634migrationschemanotchanging, PID: 27554
        java.lang.RuntimeException: Unable to start activity ComponentInfo{a.so59253634migrationschemanotchanging/a.so59253634migrationschemanotchanging.MainActivity}: android.database.sqlite.SQLiteException: near "order": syntax error (code 1 SQLITE_ERROR): , while compiling: CREATE TABLE Account_tmp (
                address TEXT NOT NULL, type TEXT, path TEXT, memo TEXT, order TEXT,
                PRIMARY KEY(address))
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
            at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
            at android.os.Handler.dispatchMessage(Handler.java:107)
            at android.os.Looper.loop(Looper.java:214)
            at android.app.ActivityThread.main(ActivityThread.java:7356)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
         Caused by: android.database.sqlite.SQLiteException: near "order": syntax error (code 1 SQLITE_ERROR): , while compiling: CREATE TABLE Account_tmp (
                address TEXT NOT NULL, type TEXT, path TEXT, memo TEXT, order TEXT,
                PRIMARY KEY(address))
            at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
            at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:986)
            at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:593)
            at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:590)
            at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:61)
            at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:33)
            at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1805)
            at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1733)
            at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.execSQL(FrameworkSQLiteDatabase.java:242)
            at a.so59253634migrationschemanotchanging.TestDatabase$Companion$MIGRATION_2_3$1.migrate(AppDatabase.kt:80)
    

    你可以使用

    `order`
    

    或者不使用 order 关键字作为列名。

    例如:-

        private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.beginTransaction()
    
                try {
                    database.execSQL(
                        """
        CREATE TABLE Account_tmp (
        address TEXT NOT NULL, type TEXT, path TEXT, memo TEXT, `order` TEXT,
        PRIMARY KEY(address))"""
                    )
    
                    database.query("SELECT * FROM Account").use { cursor ->
                        if (cursor != null && cursor.count > 0) {
                            while (cursor.moveToNext()) {
                                // cursor's column has {address, type, id, memo} (ver 1 schema), not (address, type, path, memo)(ver 2 schema) -> why??
                                val address = cursor.getString(cursor.getColumnIndex("address"))
                                val type = cursor.getString(cursor.getColumnIndex("type"))
                                val path =
                                    cursor.getString(cursor.getColumnIndex("path")) // exception because account table has not path.. still has id column
                                val memo = cursor.getInt(cursor.getColumnIndex("memo"))
    
                                val values = ContentValues()
                                values.put("address", address)
                                values.put("type", type)
                                values.put("path", path)
                                values.put("memo", memo)
                                database.insert(
                                    "Account_tmp",
                                    SQLiteDatabase.CONFLICT_FAIL,
                                    values
                                )
                            }
                        }
                    }
                    database.execSQL("DROP TABLE IF EXISTS Account")
                    database.execSQL("ALTER TABLE Account_tmp RENAME TO Account")
    
                    database.setTransactionSuccessful()
                } finally {
                    database.endTransaction()
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-24
      • 2018-03-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多