Android 上的 SQLite:android.database.sqlite.SQLiteReadOnlyDatabaseException:尝试写入只读数据库(代码 1032 SQLITE_READONLY_DBMOVED)

问题描述 投票:0回答:1

我正在尝试使用 SQLite 将 Java 项目迁移到 android,当实例化新的 MapleDBHelper 类时,出现以下异常:

尝试写入只读数据库(代码1032 SQLITE_READONLY_DBMOVED)

我在网上搜索过,但没有任何线索,是什么云的原因?

代码:

try (MapleDBHelper mapledb = MapleDBHelper.getInstance(this.context);
     SQLiteDatabase db = mapledb.getWritableDatabase()) {
     // Code Modifying DB
} catch (SQLiteException sqle) {
    Log.e("Failed to run all startup-bound database tasks", sqle.toString());
    throw new IllegalStateException(sqle);
}

DBHelper类:

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()) {
            // Delete the existing database file
            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)"
java android sqlite
1个回答
0
投票

您正在删除数据库,您不应该这样做。

当调用

onCreate
方法时,实际的数据库(除了 sqlite_master 和 android_metadata 之外是空的)已经被创建。所以它会存在,所以你总是删除它而不是创建它(如果你这样做了,无论如何都不会被指向,因为它将是另一个文件句柄)。

如果你查看 onCreate 的参数,它会将数据库传递给它。

删除代码块:-

    if (databaseFile.exists()) {
        // Delete the existing database file
        SQLiteDatabase.deleteDatabase(databaseFile);
    }
  • 数据库永远存在
    • 除了 sqlite_master(只有 android_metedata 的模式)和 android_metadata(这是一个 API 生成的表,用于存储区域设置)之外,它不会有其他表。
  • 删除数据库或文件(实际上是同一件事)将导致问题,因为文件句柄(术语可能不正确,但意味着指向文件的任何内容)将不再有效。

我认为资产名称中的

/
也可能存在问题。

  • 如果资产 sql1、sql2 .... 中有文件夹,那么我相信分隔符是
    \
    ,在字符串中需要
    "\\"
    。最好还是使用
    File.separator
    而不是
    "\\"

如果没有,我建议从文件名中删除

/

© www.soinside.com 2019 - 2024. All rights reserved.