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

5jvtdoz2  于 2023-10-14  发布在  Android
关注(0)|答案(1)|浏览(226)

我正在尝试使用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)"
67up9zun

67up9zun1#

你正在删除数据库,你不应该。
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方法,并建议注解掉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个资产文件,每个都有一个简单的表创建(除了表1,2,3和4外,所有都是一样的),例如。CREATE TABLE IF NOT EXISTS table1 (id INTEGER PRIMARY KEY, c1 TEXT);

以及以下活动代码:

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();
    }
}

当运行时,日志显示模式(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个资产创建的4个表。
和应用程序检查显示:-

相关问题