Sqlite 断电数据丢失问题排查

Sqlite 断电数据丢失

在Android 9的机器上,遇到一个问题,sqlite 数据写入完成以后,立马断电。重启以后刚刚写入的数据丢失。
初步排查,数据库同步问题,数据写入以后没有立马同步到磁盘。与数据库打开模式相关。

打开模式在SQLiteConnection这个类:
上代码.
Android 9:

  private void setWalModeFromConfiguration() {
        if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
            final boolean walEnabled =
                    (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
            // Use compatibility WAL unless an app explicitly set journal/synchronous mode
            // or DISABLE_COMPATIBILITY_WAL flag is set
            final boolean useCompatibilityWal = mConfiguration.useCompatibilityWal();
            if (walEnabled || useCompatibilityWal) {
                setJournalMode("WAL");
                if (mConfiguration.syncMode != null) {
                    setSyncMode(mConfiguration.syncMode);
                } else if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) {
                    setSyncMode(SQLiteCompatibilityWalFlags.getWALSyncMode());
                } else {
                    setSyncMode(SQLiteGlobal.getWALSyncMode());
                }
            } else {
                setJournalMode(mConfiguration.journalMode == null
                        ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode);
                setSyncMode(mConfiguration.syncMode == null
                        ? SQLiteGlobal.getDefaultSyncMode() : mConfiguration.syncMode);
            }
        }
    }

Android 12:

private void setWalModeFromConfiguration() {
        if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
            final boolean walEnabled =
                    (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
            // Use compatibility WAL unless an app explicitly set journal/synchronous mode
            // or DISABLE_COMPATIBILITY_WAL flag is set
            final boolean isCompatibilityWalEnabled =
                    mConfiguration.isLegacyCompatibilityWalEnabled();
            if (walEnabled || isCompatibilityWalEnabled) {
                setJournalMode("WAL");
                if (mConfiguration.syncMode != null) {
                    setSyncMode(mConfiguration.syncMode);
                } else if (isCompatibilityWalEnabled) {
                    setSyncMode(SQLiteCompatibilityWalFlags.getWALSyncMode());
                } else {
                    setSyncMode(SQLiteGlobal.getWALSyncMode());
                }
                maybeTruncateWalFile();
            } else {
                setJournalMode(mConfiguration.journalMode == null
                        ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode);
                setSyncMode(mConfiguration.syncMode == null
                        ? SQLiteGlobal.getDefaultSyncMode() : mConfiguration.syncMode);
            }
        }
    }

默认打开mConfiguration的属性只有openFlags被添加一个SQLiteDatabase.CREATE_IF_NECESSARY,其他都是空。

所以关键属性影响在于:

android 9:mConfiguration.useCompatibilityWal()
android12:mConfiguration.isLegacyCompatibilityWalEnabled();

android 9:

  boolean useCompatibilityWal() {
        return journalMode == null && syncMode == null
                && (openFlags & SQLiteDatabase.DISABLE_COMPATIBILITY_WAL) == 0;
    }

android12:

boolean isLegacyCompatibilityWalEnabled() {
        return journalMode == null && syncMode == null
                && (openFlags & SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL) != 0;
    }

在android 9上默认使用WAL模式,
Android 12上

    <string name="db_default_journal_mode" translatable="false">TRUNCATE</string>

所以其他几个配置:

    <string name="db_wal_sync_mode" translatable="false">NORMAL</string>
     <string name="db_default_sync_mode" translatable="false">FULL</string>

所以Android9:WAL+NORMAL。Android12:TRUNCATE+FULL.

结论来了:
sync_mode 影响,导致断电过快,数据直接丢失。

具体部分:[https://sqlite.org/pragma.html#pragma_synchronous]看官方介绍。(https://sqlite.org/pragma.html#pragma_synchronous)

解决方案:

 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
                SQLiteDatabase.OpenParams.Builder builder = new SQLiteDatabase.OpenParams.Builder();
                builder.setSynchronousMode("FULL");
                devOpenHelper.setOpenParams(builder.build());
            }

强制使用FULL 模式。
over

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值