删除房间的sqlite临时文件?

时间:2019-07-12 18:36:27

标签: android sqlite android-sqlite android-room

我的Android应用程序中有一个数据库,但是每次尝试更新(写入)数据库时,都会创建两个附加文件shmwal。特别是wal文件越来越大,即使我将相同的数据插入数据库,当我尝试获取最后修改时间时,它也困扰着我,数据仅写入wal文件中,并且不是实际的数据库。

我的问题是,如何在每次更新后强制其将数据写入数据库并删除临时文件?

3 个答案:

答案 0 :(得分:3)

  

我的问题是如何强制其将数据写入数据库   并在每次更新后删除临时文件?

是的,您可以强制/启动检查点。

关闭数据库/连接应该对其进行检查,但是从资源角度考虑可能是昂贵的(因为您必须重新打开它)。

或者您可以使用:-

PRAGMA wal_checkpoint(TRUNCATE)

但是,您应该考虑使用

PRAGMA wal_checkpoint 

在截断前后查看WAL是否忙/检查点完成了所有操作(您可能希望修改下面的示例以检查值wal_busy等(如果采用的话)(该示例来自数据库备份和数据库)已关闭))。

  

wal_checkpoint编译指示返回一行,其中包含三个整数列。第一列通常为0,但如果阻止RESTART或FULL或TRUNCATE检查点完成,则为1

我建议您阅读Write-Ahead LoggingPRAGMA Statements - PRAGMA schema.wal_checkpoint;

  

当我尝试获取上次修改时间时,数据仅写入   wal文件,而不是实际的数据库。

-wal文件就像是数据库一样被对待,并且如同被读取/更新一样,因此,如果-wal文件中有任何更改,则将从-wal文件中提取所有更改。 SQLite非常安全/坚固。

示例

以下是检查点的示例:-

public static int checkpointDB(SupportSQLiteDatabase db) {

    String TAG = "CHECKPOINTDB";
    int wal_busy = 99, wal_log = 99, wal_checkpointed =99;

    Cursor csr = db.query("PRAGMA journal_mode", null);
    if (csr.moveToFirst()) {
        String mode = csr.getString(0);
        Log.d(TAG, "Mode is " + mode);
        if (mode.toLowerCase().equals("wal")) {
            csr = db.query("PRAGMA wal_checkpoint", null);
            if (csr.moveToFirst()) {
                wal_busy = csr.getInt(0);
                wal_log = csr.getInt(1);
                wal_checkpointed = csr.getInt(2);
            }
            Log.d(TAG,"Checkpoint pre checkpointing Busy = " + String.valueOf(wal_busy) + " LOG = " + String.valueOf(wal_log) + " CHECKPOINTED = " + String.valueOf(wal_checkpointed) );
            csr = db.query("PRAGMA wal_checkpoint(TRUNCATE)", null);
            csr.getCount();
            csr = db.query("PRAGMA wal_checkpoint", null);
            if (csr.moveToFirst()) {
                wal_busy = csr.getInt(0);
                wal_log = csr.getInt(1);
                wal_checkpointed = csr.getInt(2);
            }
            Log.d(TAG,"Checkpoint post checkpointing Busy = " + String.valueOf(wal_busy) + " LOG = " + String.valueOf(wal_log) + " CHECKPOINTED = " + String.valueOf(wal_checkpointed) );
        }
    }
    csr.close();
    return wal_busy;
}

可以调用(其中 mPDB 是内置的 PersonDatabase 对象,而上面的对象在 PersonDatabase (@Database)类中) ,使用类似:-

PersonDatabase.checkpointDB(mPDB.getOpenHelper().getWritableDatabase());

一个示例用法导致:-

2019-07-13 08:15:54.997 18556-18556/s.e.s56720641roomwithmanytomany D/CHECKPOINTDB: Mode is wal
2019-07-13 08:15:54.997 18556-18556/s.e.s56720641roomwithmanytomany D/CHECKPOINTDB: Checkpoint pre checkpointing Busy = 0 LOG = 0 CHECKPOINTED = 0
2019-07-13 08:15:55.000 18556-18556/s.e.s56720641roomwithmanytomany D/CHECKPOINTDB: Checkpoint post checkpointing Busy = 0 LOG = 0 CHECKPOINTED = 0

产生:-

enter image description here

答案 1 :(得分:1)

这两个文件的存在意味着您的SQLite DB在WAL mode中运行,该机制已得到广泛的记录。 这是一种持久模式,可以通过运行以下语句一次来实现:

PRAGMA journal_mode=WAL;

请参阅第3.3节。上方链接中的“ WAL模式的持久性”。 另一个用于深入解释的有用资源:Temporary Files Used By SQLite

如果这种行为困扰您,您可以简单地发出以下声明:

PRAGMA journal_mode=DELETE;

setJournalMode(JournalMode.TRUNCATE)Android Room docs中所述。

答案 2 :(得分:0)

这是 MikeT's answer 的 Kotlin 版本:

fun SupportSQLiteDatabase.performCheckpoint(): Boolean {
    val mode = query("PRAGMA journal_mode").use { cursor ->
        if (!cursor.moveToNext()) {
            return false // not sure if this can happen
        }
        cursor.getString(0)
    }
    println("mode: $mode")
    if (mode.toLowerCase(Locale.ROOT) != "wal") {
        return false
    }
    executePragmaThenLog("PRAGMA wal_checkpoint")
    executePragmaThenLog("PRAGMA wal_checkpoint(TRUNCATE)")
    executePragmaThenLog("PRAGMA wal_checkpoint")
    return true
}

private fun SupportSQLiteDatabase.executePragmaThenLog(sql: String) {
    query(sql).use { cursor ->
        if (cursor.moveToFirst()) {
            val busy = cursor.getInt(0)
            val log = cursor.getInt(1)
            val cp = cursor.getInt(2)
            val label = sql.removePrefix("PRAGMA ")
            println("$label: busy=$busy, log=$log, checkpointed=$cp")
        }
    }
}

注意:您也可以使用 DatabaseUtils.dumpCursorToString(cursor) 来保存一些代码。