最新需要给软件做数据库读写方面的优化,之前无论读写,都是用一个 SQLiteOpenHelper.getWriteableDataBase() 来操作数据库,现在需要多线程并发读写,项目用的是2.2的SDK。
android 的数据库系统用的是sqlite ,sqlite的每一个数据库其实都是一个.db文件,它的同步锁也就精确到数据库级了,不能跟别的数据库有表锁,行锁。
所以对写实在有要求的,可以使用多个数据库文件。
哎,这数据库在多线程并发读写方面本身就挺操蛋的。
下面分析一下不同情况下,在同一个数据库文件上操作,sqlite的表现。
测试程序在2.2虚拟手机,4.2.1虚拟手机,4.2.1真手机上跑。
1,多线程写,使用一个SQLiteOpenHelper。也就保证了多线程使用一个SQLiteDatabase。
先看看相关的源码
//SQLiteDatabase.java
public long insertWithOnConflict(String table, String nullColumnHack,
ContentValues initialValues, int conflictAlgorithm) {
if (!isOpen()) {
throw new IllegalStateException("database not open");
}
.... 省略
lock();
SQLiteStatement statement = null;
try {
statement = compileStatement(sql.toString());
// Bind the values
if (entrySet != null) {
int size = entrySet.size();
Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
for (int i = 0; i < size; i++) {
Map.Entry<String, Object> entry = entriesIter.next();
DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue());
}
}
// Run the program and then cleanup
statement.execute();
long insertedRowId = lastInsertRow();
if (insertedRowId == -1) {
Log.e(TAG, "Error inserting " + initialValues + " using " + sql);
} else {
if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Inserting row " + insertedRowId + " from "
+ initialValues + " using " + sql);
}
}
return insertedRowId;
} catch (SQLiteDatabaseCorruptException e) {
onCorruption();
throw e;
} finally {
if (statement != null) {
statement.close();
}
unlock();
}
}
//SQLiteDatabase.java
private final ReentrantLock mLock = new ReentrantLock(true

本文探讨了Android中多线程环境下SQLite数据库的读写问题,包括使用单个SQLiteOpenHelper进行多线程写入时的并发控制,多线程写入时的异常情况,以及多线程读取时的锁机制。分析指出,API 11及以上版本可通过启用Write-Ahead Logging解决并发读写问题,而在更低版本中,建议使用多个数据库文件以实现并发。作者提供了一个测试程序以验证这些结论。
最低0.47元/天 解锁文章
1044

被折叠的 条评论
为什么被折叠?



