我试图用SQLite将一个Java项目迁移到Android,当实例化一个新的MapleDBHelper类时,我得到了以下异常:

attempt to write a readonly database (code 1032 SQLITE_READONLY_DBMOVED)

我在网上找了也没有头绪,是什么云造成的?

Code:

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 Class:

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)"

推荐答案

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

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

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

删除代码块:-

    if (databaseFile.exists()) {
        // Delete the existing database file
        SQLiteDatabase.deleteDatabase(databaseFile);
    }
  • 数据库将始终存在
    • 除了SQLite_MASTER(架构将只有Android_MeteData)和Android_METADATA(这是API生成的存储区域设置的表)外,它将没有其他表.
  • 删除数据库或文件(实际上是同一件事)将导致问题,因为文件句柄(术语可能不正确,但表示指向文件的任何内容)将不再有效.

使用您的代码,使用Helper中包含的convertInputStreamToString方法,并建议注释掉Of Delete,如下所示:

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;
    }
    private String convertInputStreamToString(InputStream is) {
        String str = "";
        StringBuffer buf = new StringBuffer();
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            if (is != null) {
                while((str = br.readLine())!= null) {
                    buf.append(str).append("\n");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (Throwable ignore){}
        }
        return buf.toString();
    }
}

和4个assets资源 文件,每个文件创建一个简单的表(除了表1、表2、表3和表4之外,所有文件都相同),例如CREATE TABLE IF NOT EXISTS table1 (id INTEGER PRIMARY KEY, c1 TEXT);

enter image description here

以及以下活动代码:-

public class MainActivity extends AppCompatActivity {
    MapleDBHelper _MDB;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        _MDB = MapleDBHelper.getInstance(this);
        Cursor csr = _MDB.getWritableDatabase().query("sqlite_master",null,null,null,null,null,null,null);
        DatabaseUtils.dumpCursor(csr);
        csr.close();
    }
}

运行时,日志(log)将模式(SQLite_MASTER)显示为:-

2023-10-09 19:02:15.585 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@d598771
2023-10-09 19:02:15.586 I/System.out: 0 {
2023-10-09 19:02:15.586 I/System.out:    type=table
2023-10-09 19:02:15.586 I/System.out:    name=android_metadata
2023-10-09 19:02:15.586 I/System.out:    tbl_name=android_metadata
2023-10-09 19:02:15.586 I/System.out:    rootpage=3
2023-10-09 19:02:15.586 I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
2023-10-09 19:02:15.586 I/System.out: }
2023-10-09 19:02:15.586 I/System.out: 1 {
2023-10-09 19:02:15.586 I/System.out:    type=table
2023-10-09 19:02:15.586 I/System.out:    name=table1
2023-10-09 19:02:15.586 I/System.out:    tbl_name=table1
2023-10-09 19:02:15.587 I/System.out:    rootpage=4
2023-10-09 19:02:15.587 I/System.out:    sql=CREATE TABLE table1 (id INTEGER PRIMARY KEY, c1 TEXT)
2023-10-09 19:02:15.587 I/System.out: }
2023-10-09 19:02:15.587 I/System.out: 2 {
2023-10-09 19:02:15.587 I/System.out:    type=table
2023-10-09 19:02:15.587 I/System.out:    name=table2
2023-10-09 19:02:15.587 I/System.out:    tbl_name=table2
2023-10-09 19:02:15.587 I/System.out:    rootpage=5
2023-10-09 19:02:15.587 I/System.out:    sql=CREATE TABLE table2 (id INTEGER PRIMARY KEY, c1 TEXT)
2023-10-09 19:02:15.587 I/System.out: }
2023-10-09 19:02:15.587 I/System.out: 3 {
2023-10-09 19:02:15.587 I/System.out:    type=table
2023-10-09 19:02:15.588 I/System.out:    name=table3
2023-10-09 19:02:15.588 I/System.out:    tbl_name=table3
2023-10-09 19:02:15.588 I/System.out:    rootpage=6
2023-10-09 19:02:15.588 I/System.out:    sql=CREATE TABLE table3 (id INTEGER PRIMARY KEY, c1 TEXT)
2023-10-09 19:02:15.588 I/System.out: }
2023-10-09 19:02:15.588 I/System.out: 4 {
2023-10-09 19:02:15.588 I/System.out:    type=table
2023-10-09 19:02:15.588 I/System.out:    name=table4
2023-10-09 19:02:15.588 I/System.out:    tbl_name=table4
2023-10-09 19:02:15.588 I/System.out:    rootpage=7
2023-10-09 19:02:15.588 I/System.out:    sql=CREATE TABLE table4 (id INTEGER PRIMARY KEY, c1 TEXT)
2023-10-09 19:02:15.589 I/System.out: }
2023-10-09 19:02:15.589 I/System.out: <<<<<

即Android_METADATA表和从4个assets资源 创建的4个表.

和应用判断显示:-

enter image description here

Java相关问答推荐

那么比较似乎不是词典学的,尽管doctor 这么说

为什么如果数组列表中有重复项,我的代码SOMETIMES不返回true?

缩小画布比例后更改滚动窗格的内部大小

Java .类参数不通过构造函数传递

Java FX中的河内之塔游戏-在游戏完全解决之前什么都不会显示

Jakarta CDI强制bean构造/注册遗留事件侦听器

Helidon 4和Http API

如何让JavaFx应用程序识别依赖项?

使用多个RemoteDatabase对象的一个线程

如何集成语义发布和BitBucket(Java项目)

如何仅使用键/ID的一部分(组合)高效地返回映射值?

如何在Cosmos DB(Java SDK)中增加默认响应大小

内存和硬盘中的Zip不同,这会导致下载后的Zip损坏

由于在生成器模式中使用泛型,lambda表达式中的返回类型错误

在Frege中,我如何将一个字符串安全地转换为一个可能的Int?

为什么StandardOpenOption.CREATE不能通过Ubuntu在中小企业上运行?

如何在IntelliJ IDEA的Build.sbt中添加外部JAR文件?

嘲笑黄瓜中的对象

spring 数据Elastic search 与 spring 启动数据Elastic search 之间的区别是什么?

[Guice/MissingImplementation]:未绑定任何实现