一个SQLiteReadOnlyDatabaseException的问题

来源:互联网 发布:ff14人族捏脸数据分享 编辑:程序博客网 时间:2024/06/05 03:33

最近测试同事上报了随机的一个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对象就会生成,后续如果有清除该程序数据的操作就会导致这个问题。至于为啥会清除数据那就是另外的问题了。


原创粉丝点击