这是插入代码:
public void insertOrIgnore(ContentValues values) { sqliteDatabase db = this.dbHelper.getWritableDatabase(); try { //I added these null value checks to stop NPE,but doesn't help. if (values != null && db != null) { db.insertWithOnConflict(TABLE,null,values,sqliteDatabase.CONFLICT_IGnorE); } } catch (sqliteException e) { } finally { if (db != null) { db.close(); } } }
哪里
public static final String TABLE = "albums";
大多数情况下,此代码使用按预期添加到数据库的数据.但是,它有时很少产生以下错误.堆栈跟踪来自ACRA,我无法隔离此错误发生的条件.我正在寻找指示为什么会发生这种情况以及条件是什么.我对sqlite的了解是初学者的.
java.lang.NullPointerException at android.database.sqlite.sqliteStatement.releaseAndUnlock(sqliteStatement.java:290) at android.database.sqlite.sqliteStatement.executeUpdateDelete(sqliteStatement.java:96) at android.database.sqlite.sqliteDatabase.executesql(sqliteDatabase.java:2025) at android.database.sqlite.sqliteDatabase.execsql(sqliteDatabase.java:1965) at android.database.sqlite.sqliteDatabase.beginTransaction(sqliteDatabase.java:690) at android.database.sqlite.sqliteDatabase.beginTransactionNonExclusive(sqliteDatabase.java:605) at android.database.sqlite.sqliteStatement.acquireAndLock(sqliteStatement.java:247) at android.database.sqlite.sqliteStatement.executeInsert(sqliteStatement.java:112) at android.database.sqlite.sqliteDatabase.insertWithOnConflict(sqliteDatabase.java:1844) at com.mydomain.myapp.albums.AlbumsData.insertOrIgnore(AlbumsData.java:89)
第89行是上面显示的db.insertWithOnConflict(…)调用.
我不是在寻找一个完整代码的答案,而是一个指针和解释什么是错误的,所以我可以自己开始修复它.
编辑:
堆栈跟踪显示NPE源自SQLiteStatement的第290行(v 4.03):
setNativeHandle(mDatabase.mNativeHandle);
所以似乎数据库实例为null.当我在事务开始时测试null时,它如何在事务期间变为空?
解决方法
您的错误原因可能是您在某个时刻关闭了数据库.可能同时失败的任务没有完成.
我跟踪了堆栈跟踪,这是大致发生的事情:
> AlbumsData.insertOrIgnore(AlbumsData.java:89)
您调用insertWithOnConflict,它构建生成的sql字符串(“INSERT OR IGnorE INTO …”),然后将其与ContentValues中的值一起包装到sqliteStatement中.
> sqliteDatabase.insertWithOnConflict(sqliteDatabase.java:1844) – 生成的语句现在将被执行
> sqliteStatement.executeInsert(sqliteStatement.java:112) – 在实际插入发生之前,数据库需要获取锁.
> sqliteStatement.acquireAndLock(sqliteStatement.java:247) – 这里发生了一些检查,数据库对象就此而言在那时我看不到null.代码决定它必须启动一个事务.数据库对象本身就是我看不到的那一点.
> sqliteDatabase.beginTransactionNonExclusive(sqliteDatabase.java:605) – 只是转发
> sqliteDatabase.beginTransaction(sqliteDatabase.java:690) – 经过一些检查(不确定数据库是否必须存在),它将尝试执行execsql(“BEGIN IMMEDIATE;”)
> sqliteDatabase.execsql(sqliteDatabase.java:1965) – 只需转发
> sqliteDatabase.executesql(sqliteDatabase.java:2025) – 从“BEGIN IMMEDIATE”开始构建另一个sqliteStatement;这个应该立即执行
> sqliteStatement.executeUpdateDelete(sqliteStatement.java:96) – 从检查数据库锁开始,这似乎没问题,数据库不应该为null.然后执行该语句,最后再次解锁数据库.
> sqliteStatement.releaseAndUnlock(sqliteStatement.java:290) – 清理一些东西,最后因NPE而失败,因为数据库为空.
BEGIN TRANSACTION IMMEDIATE; -- crash INSERT INTO table (...) VALUES (...); -- (end transaction)
这在我看来是一个框架错误.在那里内部处理的数据库对象不应该在某个地方是空的,特别是当它似乎在堆栈中没有进一步为空时.
我也认为另一个隐藏的异常可能是导致此问题的根本原因.代码中有很多try {/ * do stuff * /}最后{/ *清理* /}块,即使try部分抛出异常,也会执行finally部分.现在finally块可能导致另一个异常,结果是AFAIK,原始异常被finally块中的新异常替换.
特别是executeUpdateDelete()就像
try { acquireAndLock(WRITE); // actual statement execution } finally { releaseAndUnlock(); }
如果数据库在此时关闭,则acquireAndLock或try部分中的任何代码都可能失败,这可能使数据库对象保持为null,从而导致releaseAndUnlock再次失败.你应该得到相同的堆栈跟踪.
除此之外,不要像catch(sqliteException e){/ * empty * /}那样执行空的catch块.如果可能,请使用ACRA记录它们/您不要这样做.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。