Comments (2)
异常详情
android.database.sqlite.SQLiteDiskIOException: disk I/O error - SQLITE_IOERR_WRITE (Sqlite code 778), (OS error - 9:Bad file descriptor)
at android.database.sqlite.SQLiteConnection.nativeExecute(Native Method)
at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:563)
at android.database.sqlite.SQLiteSession.endTransactionUnchecked(SQLiteSession.java:437)
at android.database.sqlite.SQLiteSession.endTransaction(SQLiteSession.java:401)
at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:541)
at com.xtc.im.core.push.store.dao.ServerConfigDao.update(Unknown Source)
at com.xtc.im.core.push.domain.DomainManager.updateOnConnectSuccess(Unknown Source)
at com.xtc.im.core.push.PushService$1$1.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:743)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:150)
at android.os.HandlerThread.run(HandlerThread.java:61)
资料查询
https://www.sqlite.org/rescode.html
官方解释
The SQLITE_IOERR_WRITE error code is an extended error code for SQLITE_IOERR indicating an I/O error in the VFS layer while trying to write into a file on disk. This error might result from a hardware malfunction or because a filesystem came unmounted while the file was open. This error should not occur if the filesystem is full as there is a separate error code (SQLITE_FULL) for that purpose.
获取信息
- 设备故障导致
- 文件打开时正在卸载文件系统导致
from androidbox.
异常详情
pro5 出现1次
java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/user/0/com.xtc.watch/databases/xtc_im.db
at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:522)
at com.xtc.im.core.push.store.dao.ServerConfigDao.update(Unknown Source)
at com.xtc.im.core.push.domain.DomainManager.updateOnConnectFailed(Unknown Source)
at com.xtc.im.core.push.PushService$1$4.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.os.HandlerThread.run(HandlerThread.java:61)
应用代码
public void update(DBServerConfigEntity entity) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 事务开始
db.beginTransaction();
Cursor cursor = null;
try {
cursor = db.query(DBServerConfigEntity.TABLE, null, DBServerConfigEntity.KEY_ID + "=?", new String[]{String.valueOf(entity.getId())}, null, null, null);
DBServerConfigEntity oldEntity = null;
if (cursor == null) {
LogUtil.e(TAG,"cursor is null ,the config we update is not exist !!!");
return;
}
if (cursor.moveToFirst()) {
oldEntity= serverConvertToEntity(cursor);
}
if (oldEntity == null) {
LogUtil.e(TAG,"old server config is null ,the config we update is not exist !!!");
return;
}
ContentValues values = serverConvertToValues(entity, oldEntity);
db.update(DBServerConfigEntity.TABLE, values, DBServerConfigEntity.KEY_ID + "=?", new String[]{String.valueOf(entity.getId())});
// 事务 成功
db.setTransactionSuccessful();
} catch (Exception e) {
LogUtil.e(TAG, e);
} finally {
// 事务结束
db.endTransaction();
if (cursor != null) {
cursor.close();
}
}
}
源码追踪
SQLiteDatabase.java
public void endTransaction() {
acquireReference();
try {
getThreadSession().endTransaction(null);
} finally {
releaseReference();
}
}
public void acquireReference() {
synchronized(this) {
if (mReferenceCount <= 0) {
throw new IllegalStateException(
// 抛出异常
"attempt to re-open an already-closed object: " + this);
}
mReferenceCount++;
}
}
原因分析
我们和数据库只能有一条连接,即我们在调用dbHelper.getWritableDatabase()返回的是同一个对象,也就意味着我们在不同的线程需要用同一个dbHelper获取db。否则会报:android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5) 。
有可能在别处调用了db.close方法,最终会调用releaseReference方法,导致mReferenceCount减一,当上述执行endTransaction时发现mReferenceCount<=0,就抛出了该异常。
解决方案
- 不关法:用完不关闭(调用db.close方法),连接一直开着,不过存在性能的影响,观察源码可知。
public void releaseReference() {
boolean refCountIsZero = false;
synchronized(this) {
refCountIsZero = --mReferenceCount == 0;
}
if (refCountIsZero) {
// 当应用层没有连接的时候调用这里,去释放数据库连接
onAllReferencesReleased();
}
}
- 计数法:
在外部添加一个获取连接的管理类,并进行计数,每打开一个加1,用完减1,如果没有了则调用关闭连接,调用db.close。
参考文章android sqlite数据库并发问题的详细描述和解决方案
知识扩展
AndroidSQLite的事务机制,保障了数据修改的准确性,避免出现脏数据。通过beginTransaction开启一个事务,然后执行自己的数据库操作语句,如果顺利执行完,就会执行setTransactionSuccessful,此时设置了一个标志位 mTransactionStack.mMarkedSuccessful = true。最后执行endTransaction,会进行前面标志位的判断,如果为true表明此次操作没有问题。就执行“COMMIT”提交数据,否则执行“ROLLBACK”,将数据回滚到本次事务操作之前的状态。
SQLiteSession#setTransactionSuccessful
public void setTransactionSuccessful() {
throwIfNoTransaction();
throwIfTransactionMarkedSuccessful();
// 事务顺利结束 在此设置成功的标志位
mTransactionStack.mMarkedSuccessful = true;
}
SQLiteSession#endTransactionUnchecked
private void endTransactionUnchecked(CancellationSignal cancellationSignal, boolean yielding) {
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
}
final Transaction top = mTransactionStack;
boolean successful = (top.mMarkedSuccessful || yielding) && !top.mChildFailed;
RuntimeException listenerException = null;
final SQLiteTransactionListener listener = top.mListener;
if (listener != null) {
try {
if (successful) {
listener.onCommit(); // might throw
} else {
listener.onRollback(); // might throw
}
} catch (RuntimeException ex) {
listenerException = ex;
successful = false;
}
}
mTransactionStack = top.mParent;
recycleTransaction(top);
if (mTransactionStack != null) {
if (!successful) {
mTransactionStack.mChildFailed = true;
}
} else {
try {
if (successful) {
// 事务成功 则提交
mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
} else {
// 事务失败 则回滚
mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
}
} finally {
releaseConnection(); // might throw
}
}
if (listenerException != null) {
throw listenerException;
}
}
from androidbox.
Related Issues (20)
- Toast Show的时候出现 BadTokenException: Unable to add window -- token
- java.lang.IllegalStateException: Fragment already added HOT 2
- ANR: "main" prio=5 tid=1 WaitingForGcToComplete HOT 2
- Exception: The specified message queue synchronization barrier token has not been posted or has already been removed.
- ExceptionInInitializerError HOT 2
- 为什么Receiver不允许进行BindService
- Fragment生命周期
- SQLite多线程问题 HOT 3
- 《Android应用性能优化》 HOT 1
- 内存优化 HOT 1
- Native闪退 HOT 1
- java.lang.IllegalStateException: The specified child already has a parent.
- RxJava线程 HOT 1
- Service启动成功onCreate和onStartCmmand都不回调
- CursorWindowAllocationException HOT 1
- SharedPreferences解析
- Component class com.huawei.hms.support.api.push.PushEventReceiver does not exist in com.xtc.watch HOT 2
- SQLite查询操作源码分析:从 IllegalArgumentException:the bind value at index 2 is null 说起
- startActivityForResult的坑
- java.lang.IllegalArgumentException: pointerIndex out of range HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from androidbox.