Android Studio中SQLiteOpenHelper添加删库方法后出现只读异常求助
问题原因分析
你遇到的SQLiteReadOnlyDatabaseException (code 1032),核心原因是在数据库连接处于打开状态时强行删除了数据库文件:
你的logdb类在成员变量位置直接初始化了SQLiteDatabase db=this.getWritableDatabase();,这意味着只要logdb对象存在,这个数据库连接就会一直保持打开状态。当你调用drop()方法里的c.deleteDatabase("login.db")时,SQLite检测到当前正在使用的数据库文件被删除,为了避免数据损坏,会自动将当前的数据库连接标记为只读状态,后续再用这个db实例执行插入、修改等写操作,就会触发只读错误。
修复方案
方案1:先关闭连接再删除数据库文件
如果确实需要删除整个数据库,必须先关闭所有打开的连接,再执行删除操作。修改drop()方法如下:
public String drop(){ try { // 先关闭已打开的数据库连接 if(db != null && db.isOpen()){ db.close(); } // 删除数据库文件 c.deleteDatabase("login.db"); // 重置数据库实例,后续使用时重新获取连接 db = this.getWritableDatabase(); } catch(Exception e) { e.printStackTrace(); } return "操作完成"; }
方案2:直接删除指定表(更推荐)
如果你只是想删除user表而非整个数据库,完全不需要删除数据库文件,直接执行SQL语句即可,不会影响现有连接:
public String dropUserTable(){ try { db.execSQL("DROP TABLE IF EXISTS user;"); // 如需重建表,可调用已有的createuser()方法 createuser(); } catch(Exception e) { e.printStackTrace(); } return "表删除完成"; }
额外代码优化建议
你的代码还有几个潜在问题,建议同步修复:
- 成员变量
SQLiteDatabase db不要在构造函数之前初始化,应移到super调用之后,确保上下文初始化完成:Context c; SQLiteDatabase db; public logdb(@Nullable Context context){ super(context, "login.db", null, 1); this.c = context; db = this.getWritableDatabase(); // 移到super调用之后 try { String st = "create table if not exists user(email text,password text,username text)"; db.execSQL(st); } catch(Exception e){ e.printStackTrace(); } } - 插入数据不要用字符串拼接的方式,容易引发SQL注入,改用
insert()方法或带占位符的execSQL:public void oninsert(ContentValues cv){ try { // 推荐使用insert方法,更安全简洁 db.insert("user", null, cv); // 或者用带占位符的execSQL写法 // db.execSQL("insert into user(email,password,username) values(?,?,?)", // new Object[]{cv.get("email"), cv.get("password"), cv.get("username")}); } catch(Exception e) { e.printStackTrace(); } } getusername()方法需处理游标为空的情况,并记得关闭游标避免内存泄漏:public String getusername(){ Cursor c = db.rawQuery("select * from user",null); String username = ""; if(c.moveToFirst()){ // 用moveToFirst判断数据存在更可靠 username = c.getString(2); } c.close(); // 游标使用完毕必须关闭 return username; }
内容的提问来源于stack exchange,提问作者Arun D Tej
相关产品推荐
相关产品推荐

