最新需要给软件做数据库读写方面的优化,之前无论读写,都是用一个 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 ReentrantL