一个SQLiteReadOnlyDatabaseException的问题

本文分析了一种特殊的SQLite数据库异常——SQLiteReadOnlyDatabaseException,并详细解释了code1032(SQLITE_READONLY_DBMOVED)错误码的原因及解决方案。指出此问题并非数据库只读,而是由于数据库文件被移动导致。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近测试同事上报了随机的一个crash问题,看日志是SQLiteReadOnlyDatabaseException的问题,发生在update数据库的时候。我自己写的ContentProvider代码就是在程序目录下放置数据,所以不是网上常见的缺少写sd卡权限的原因。具体分析要看日志:

06-08 10:31:46.358  1913  1913 E AndroidRuntime: android.database.sqlite.SQLiteReadOnlyDatabaseException: attempt to write a readonly database (code 1032)
06-08 10:31:46.358  1913  1913 E AndroidRuntime: 	at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
06-08 10:31:46.358  1913  1913 E AndroidRuntime: 	at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:741)
06-08 10:31:46.358  1913  1913 E AndroidRuntime: 	at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754)
06-08 10:31:46.358  1913  1913 E AndroidRuntime: 	at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
06-08 10:31:46.358  1913  1913 E AndroidRuntime: 	at android.database.sqlite.SQLiteDatabase.updateWithOnConflict(SQLiteDatabase.java:1606)
06-08 10:31:46.358  1913  1913 E AndroidRuntime: 	at android.database.sqlite.SQLiteDatabase.update(SQLiteDatabase.java:1552)
06-08 10:31:46.358  1913  1913 E AndroidRuntime: 	at com.hb.provider.HbSettingProvider.update(HbSettingProvider.java:90)
06-08 10:31:46.358  1913  1913 E AndroidRuntime: 	at android.content.ContentProvider$Transport.update(ContentProvider.java:366)
06-08 10:31:46.358  1913  1913 E AndroidRuntime: 	at android.content.ContentResolver.update(ContentResolver.java:1411)
日志中有个code 1032,这个会提供更具体的信息,网络搜索到信息如下:

SQL return code 1032 SQLITE_READONLY_DBMOVED
The SQLITE_READONLY_DBMOVED error code is an extended error code for SQLITE_READONLY. The SQLITE_READONLY_DBMOVED error code indicates that a database cannot be modified because the database file has been moved since it was opened, and so any attempt to modify the database might result in database corruption if the processes crashes because the rollback journal would not be correctly named.

看出这个真正的原因是物理数据库文件已被移除,和SQLiteReadOnlyDatabaseException的字面意思有差距,并不是数据库只读。

参见SQLiteOpenHelper源码

frameworks/base/core/java/android/database/sqlite/SQLiteOpenHelper.java

    public SQLiteDatabase getWritableDatabase() {
        synchronized (this) {
            return getDatabaseLocked(true);
        }
    }

    private SQLiteDatabase getDatabaseLocked(boolean writable) {
        if (mDatabase != null) {
            if (!mDatabase.isOpen()) {
                // Darn!  The user closed the database by calling mDatabase.close().
                mDatabase = null;
            } else if (!writable || !mDatabase.isReadOnly()) {
                // The database is already open for business.
                return mDatabase;
            }
        }
        ...
    }
可以看出如果mDataBase已经被打开过的话,会直接返回mDataBase对象,并没有判断数据库文件已经被删除的情况。

会发生此种现象的原因是ContentProvider运行在常驻进程中,有过一次数据库操作后mDataBase对象就会生成,后续如果有清除该程序数据的操作就会导致这个问题。至于为啥会清除数据那就是另外的问题了。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值