【问题标题】:How to solve the issue SQLiteException: no such table: Cars (code 1 SQLITE_ERROR): , while compiling: SELECT DISTINCT * FROM Cars?如何解决问题 SQLiteException: no such table: Cars (code 1 SQLITE_ERROR): , while compile: SELECT DISTINCT * FROM Cars?
【发布时间】:2020-03-10 20:31:52
【问题描述】:

我正在我的应用程序中使用 SQLite,并试图将备份的数据库导入应用程序。一切都适用于 Oreo 及以下 SDK 版本(直到 SDK 16),但不适用于 Android P 及更高版本。我的数据库:

    private val dbTemp = DB_NAME + "_tmp"
    private val dbBackup = context.openOrCreateDatabase(dbTemp, Context.MODE_PRIVATE, null)

    override fun onCreate(db: SQLiteDatabase) {
            db.execSQL("CREATE TABLE $TABLE ($ID INTEGER PRIMARY KEY AUTOINCREMENT, $TITLE TEXT, $CAR TEXT, $DATE TEXT);")
        }

        override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
            db.execSQL("DROP TABLE IF EXISTS $TABLE")
            onCreate(db)
        }

我正在通过替换当前数据库来应对备份的数据库,如下所示:

private fun copyData() {
        db.delete(TABLE, null, null)
        val cursor = dbBackup.query(  // <- here occurs the problem!
            true,
            TABLE,
            null,
            null,
            null,
            null,
            null,
            null,
            null
        )
        cursor.moveToFirst()
        while (!cursor.isAfterLast) {
            db.insert(TABLE, null, modelToValues(cursorToModel(cursor)))
            cursor.moveToNext()
        }
        cursor.close()
        context.deleteDatabase(dataTmp)
    }

这是抛出的问题:

Process: com.example.cars, PID: 18674
        android.database.sqlite.SQLiteException: no such table: Cars (code 1 SQLITE_ERROR): , while compiling: SELECT DISTINCT * FROM Cars
            at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
            at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:903)
            at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:514)
            at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
            at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
            at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
            at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
            at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1408)
            at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1255)
            at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1126)
            at com.easyapps.cryptnote.ListDatabase.copyData(CarsDatabase.kt:163)
            at com.easyapps.cryptnote.ListDatabase.importToApp(CarsDatabase.kt:155)
            at com.example.cars.BackupActivity$onCreate$3$$special$$inlined$apply$lambda$2.onClick(BackupActivity.kt:104)
            at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:172)
            at android.os.Handler.dispatchMessage(Handler.java:106)
            at android.os.Looper.loop(Looper.java:193)
            at android.app.ActivityThread.main(ActivityThread.java:6669)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

我尝试将这些链接 linklink 的解决方案结合起来,但没有成功。 有关更多信息,我的数据库解决方案的备份和导入是基于这个 demo project,它太旧了,但是我可以将它用于我在 Kotlin 中的项目。

备份方法:

fun exportToSD() {
        createFolderOnSD()
        val data = Environment.getDataDirectory()
        val backupDbPath = File(sdFolder, "/(${utilities.getDate("dd_MM_yyyy_HH_mm")}) " + DB_NAME)

        try {
            val source = FileInputStream(File(data, currentDbPath)).channel
            val destination = FileOutputStream(backupDbPath).channel
            destination.transferFrom(source, 0, source.size())
            source.close()
            destination.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

导入到App方法:

fun importToApp(fileNameOnSD: String) {
        val sd = File(sdFolder)
        if (sd.canWrite()) {
            val currentDB = File(Environment.getDataDirectory(), dataTmp)
            val backupDB = File(sd, fileNameOnSD)

            if (currentDB.exists()) {
                try {
                    val src = FileInputStream(backupDB).channel
                    val dst = FileOutputStream(currentDB).channel
                    dst.transferFrom(src, 0, src.size())
                    src.close()
                    dst.close()
                } catch (e: FileNotFoundException) {
                    e.printStackTrace()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
        copyData()
    }

【问题讨论】:

  • 所以,我发布了解决方案here

标签: android sqlite kotlin


【解决方案1】:

您可以通过将以下内容添加到您的 SQLiteOpenHelper 类来禁用Write Ahead Logging 选项(注意onConfigure 而不是onOpen 中的其他链接答案) - 这适用于我的应用程序。

// Called when the database connection is being configured.
    // Configure database settings for things like foreign key support, write-ahead logging, etc.
    @Override
    public void onConfigure(SQLiteDatabase db) {
        super.onConfigure(db);
        // Later version of Android seem to enable writeAhead by default, so for consistency explicitly disable it
        db.disableWriteAheadLogging();
    }

【讨论】:

    【解决方案2】:

    当您进行备份时,-wal 文件(以 -wal 为后缀的数据库文件名)不是空的,也没有与数据库文件一起备份/恢复?

    您所描述的问题的症状是 -wal 文件不为空(完全检查点)且未备份并随后恢复。

    使用 WAL 模式备份数据库的正确方法是备份数据库文件和 -wal 文件并恢复两者,或者确保数据库是完全检查点的(即 -wal 文件中的更改具有已应用于数据库文件),然后只需要备份数据库文件。

    • 关闭所有数据库连接将完全检查数据库。

    这背后的原因是 Android 9+ 的默认模式是 WAL(预写日志)而不是日志。通过日志模式,更改将应用​​于数据库,并且这些更改的日志/日志存储在日志文件中。日志文件的丢失意味着您无法回滚更改。在 WAL 模式下,更改被写入 WAL 文件,该文件实际上是数据库的一部分。如果 WAL 文件丢失,那么更改最多也将丢失。

    【讨论】:

    • 非常感谢您的回答。我真的不明白如何管理 WAL。我尝试使用 Ramon 提供的answer。该解决方案应该禁用 WAL,但仍然无法正常工作。请看一下,我加了个和平码,我是怎么做备份的。很遗憾,我无法分享整个应用程序代码,但我会尽量提供所有必要的信息。
    【解决方案3】:

    在copyData()方法复制数据后尝试调用db.close()一次

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-20
      • 1970-01-01
      • 1970-01-01
      • 2013-05-22
      相关资源
      最近更新 更多