当我在多线程环境当中使用数据库的时候遇到了这个问题。这是我之间在 StackOverflow 上面的回答的答案:Avoiding Connection Pool Closed in SQLite。
因为同一个 SQLiteOpenHelper 的 getWritableDatabase() 返回同一个 SQLiteDatabase 对象,所以当在多线程环境当中使用 SQLiteDatabase 的时候就,如果一个线程关闭了 SQLiteDatabase 而另一个线程只在使用它就会出现 SQLiteConnectionPool close exception。我在之前的回答也分析过这个问题:java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed。
所以,当我们在 Android 中使用数据库的时候,可以按照下面的方式设计:
// the PalmDB is your Helper name
class PalmDB extends SQLiteOpenHelper {
private static PalmDB sInstance = null;
public static PalmDB getInstance(final Context context){
if (sInstance == null){
synchronized (SQLiteOpenHelper.class) {
if (sInstance == null) {
// be sure to call getApplicationContext() to avoid memory leak
sInstance = new PalmDB(context.getApplicationContext());
}
}
}
return sInstance;
}
// ... next is the code for your insert method:
protected SQLiteDatabase getDatabase() {
OpenHelperManager.requireConnection();
return getWritableDatabase();
}
protected void closeDatabase() {
OpenHelperManager.releaseHelper(this);
}
/*
* Note that in this method, I didn't call getWriteDatabse() and SQLiteDatabase.close()
* to open and close db connection, instead I used two methods and added some options there.
*/
public synchronized void insert(int deviceid, int productid) {
SQLiteDatabase sqLiteDatabase = getDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("deviceid", deviceid);
contentValues.put("productid", productid);
sqLiteDatabase.insert(payment_table, null, contentValues);
closeDatabase();
}
}
这里我们使用单例的 PalmDB 来操作数据库。并定义了一个工具类 SQLiteOpenHelper 来管理数据库的连接:
public class OpenHelperManager {
@SuppressLint("StaticFieldLeak")
private static boolean isClosed = false;
private static int instanceCount = 0;
public static synchronized void releaseHelper(PalmDB helper) {
instanceCount--;
LogUtils.e(String.format("releasing helper %s, instance count = %s", helper, instanceCount));
if (instanceCount <= 0) {
if (helper != null) {
LogUtils.e(String.format("zero instances, closing helper %s", helper));
helper.close();
isClosed = true;
}
if (instanceCount < 0) {
LogUtils.e(String.format("too many calls to release helper, instance count = %s", instanceCount));
}
}
}
public static synchronized void requireConnection() {
isClosed = false;
instanceCount++;
}
public static boolean isClosed() {
return isClosed;
}
}
当创建和断开数据库连接的时候,我们都会在 SQLiteOpenHelper 中进行记录。并且当所有的连接都关闭的时候,我们就关闭 PalmDB。
以上是一种解决方案,在我的开源项目中,我们自己设计了一套数据库访问的逻辑,你可以通过 Github 来参考它的代码:马克笔记。