You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android迁移SQLite项目遇SQLITE_READONLY_DBMOVED(1032)错误求因

问题:Android SQLite迁移出现SQLITE_READONLY_DBMOVED异常

我将Java项目迁移至Android平台并使用SQLite时,实例化MapleDBHelper类遇到如下异常:
attempt to write a readonly database (code 1032 SQLITE_READONLY_DBMOVED)
网上搜索未找到有效解决线索,请教可能的原因。

调用代码

try (MapleDBHelper mapledb = MapleDBHelper.getInstance(this.context);
     SQLiteDatabase db = mapledb.getWritableDatabase()) {
     // 修改数据库的代码
} catch (SQLiteException sqle) {
    Log.e("Failed to run all startup-bound database tasks", sqle.toString());
    throw new IllegalStateException(sqle);
}

MapleDBHelper类代码

public class MapleDBHelper extends SQLiteOpenHelper {
    public Context context;
    private static final String DATABASE_NAME = "cosmic";
    private static final int DATABASE_VERSION = 1;
    private static MapleDBHelper sInstance;
    private MapleDBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.context = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        File databaseFile = context.getDatabasePath(DATABASE_NAME);
        if (databaseFile.exists()) {
            // 删除已有数据库文件
            SQLiteDatabase.deleteDatabase(databaseFile);
        }

        try {
            AssetManager assetManager = context.getAssets();
            InputStream db_database = assetManager.open("sql/1_db_database.sql");
            InputStream db_drops = assetManager.open("sql/2_db_drops.sql");
            InputStream db_shopupdate = assetManager.open("sql/3_db_shopupdate.sql");
            InputStream db_admin = assetManager.open("sql/4_db-admin.sql");
            db.execSQL(convertInputStreamToString(db_database));
            db.execSQL(convertInputStreamToString(db_drops));
            db.execSQL(convertInputStreamToString(db_shopupdate));
            db.execSQL(convertInputStreamToString(db_admin));

            db_database.close();
            db_drops.close();
            db_shopupdate.close();
            db_admin.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException("Could not read database file : " + e.getMessage());
        } catch (IOException e) {
            throw new RuntimeException("Could not successfully parse database file " + e.getMessage());
        }
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }

    public static synchronized MapleDBHelper getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new MapleDBHelper(context.getApplicationContext());
        }
        return sInstance;
    }
}

堆栈信息

Stacktrace:
0 = {StackTraceElement@17117} "android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)"
1 = {StackTraceElement@17118} "android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:890)"
2 = {StackTraceElement@17119} "android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:756)"
3 = {StackTraceElement@17120} "android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:66)"
4 = {StackTraceElement@17121} "android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1920)"
5 = {StackTraceElement@17122} "android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1841)"
6 = {StackTraceElement@17123} "android.database.sqlite.SQLiteDatabase.setVersion(SQLiteDatabase.java:1102)"
7 = {StackTraceElement@17124} "android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:419)"
8 = {StackTraceElement@17125} "android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)"
9 = {StackTraceElement@17126} "net.server.Server.init(Server.java:897)"
10 = {StackTraceElement@17127} "net.server.Server.main(Server.java:1017)"
11 = {StackTraceElement@17128} "com.mapleserver.MainActivity.startMapleServer(MainActivity.kt:34)"
12 = {StackTraceElement@17129} "com.mapleserver.MainActivity.onCreate(MainActivity.kt:28)"

原因分析及解决办法

核心问题

SQLITE_READONLY_DBMOVED异常的本质是:SQLite已打开某数据库文件,但该文件被移动或删除,导致后续写入操作失败。

你的onCreate方法存在致命错误:当onCreate被调用时,SQLiteOpenHelper已经打开了数据库连接(方法参数db就是已打开的实例),此时你直接删除了底层的数据库文件databaseFile。SQLite的连接仍指向原文件路径,但文件已不存在,后续执行execSQL或系统自动执行的setVersion操作时,就会触发只读异常。

解决步骤

  1. 移除onCreate中删除数据库文件的代码
    onCreate被调用的前提是数据库文件原本不存在(或版本不匹配触发重建),此时根本不需要删除已有文件——如果文件存在,SQLiteOpenHelper不会调用onCreate,而是直接打开数据库。

    修改后的onCreate方法:

    @Override
    public void onCreate(SQLiteDatabase db) {
        try {
            AssetManager assetManager = context.getAssets();
            InputStream db_database = assetManager.open("sql/1_db_database.sql");
            InputStream db_drops = assetManager.open("sql/2_db_drops.sql");
            InputStream db_shopupdate = assetManager.open("sql/3_db_shopupdate.sql");
            InputStream db_admin = assetManager.open("sql/4_db-admin.sql");
            db.execSQL(convertInputStreamToString(db_database));
            db.execSQL(convertInputStreamToString(db_drops));
            db.execSQL(convertInputStreamToString(db_shopupdate));
            db.execSQL(convertInputStreamToString(db_admin));
    
            db_database.close();
            db_drops.close();
            db_shopupdate.close();
            db_admin.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException("无法读取数据库文件 : " + e.getMessage());
        } catch (IOException e) {
            throw new RuntimeException("解析数据库文件失败 " + e.getMessage());
        }
    }
    
  2. 重置数据库需在外部处理
    若确实需要重置数据库(如版本更新、用户手动重置),需在打开数据库之前删除文件,而非在onCreate内部操作:

    // 重置数据库的方法,需在调用getWritableDatabase前执行
    public static void resetDatabase(Context context) {
        File dbFile = context.getDatabasePath(DATABASE_NAME);
        if (dbFile.exists()) {
            SQLiteDatabase.deleteDatabase(dbFile);
            // 重置单例,让下次getInstance创建新的Helper实例
            sInstance = null;
        }
    }
    
  3. 检查文件权限
    确保应用对数据库目录有写入权限,Android 10+默认使用Scoped Storage,SQLiteOpenHelper的默认路径为应用私有目录,权限通常无需额外配置;若自定义路径,需确认对应目录的写入权限。

内容的提问来源于stack exchange,提问作者k0ala Xing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 00:40:55