避免在SQLite中关闭连接池

时间:2017-10-23 14:39:47

标签: java android android-sqlite

我收到如下错误:

Exception java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.

原因是当我从表中获取数据时,巧合的是另一个服务开始运行以插入数据并且按照SQLite逻辑,插入命令关闭连接并且从表读取数据的服务得到连接池关闭错误

有人可以帮助我如何处理这个问题?我没有在所有设备上收到此错误。只有少数设备,有时也是如此。

我读了一些关于使用setWriteAheadLoggingEnabled(true)的问题。这是我可以在我的类构造函数中使用的吗?

我在DatabasWorking类中的插入方法,我从不同的类调用以插入数据。

public void insert(int deviceid, int productid) {
      SQLiteDatabase  sqLiteDatabase = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put("deviceid", deviceid);
        contentValues.put("productid", productid);
        sqLiteDatabase.insert(payment_table, null, contentValues);
        sqLiteDatabase.close();

    }

现在如何在此方法中使用单例。我需要在这里改变一下吗?

1 个答案:

答案 0 :(得分:2)

我从multi-theads环境查询数据库时遇到了这个问题。由于getWritableDatabase()为同一个SQLiteOpenHelper返回相同的SQLiteDatabase对象,如果在一个线程中关闭它而另一个线程使用它,则会导致SQLiteConnectionPool关闭异常。我在这里分析了我的案例:java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed

以下是您的代码建议:

从您的代码判断它可能存在于SQLiteOpenHelper对象中。您需要将其设为单例,因为一个SQLiteOpenHelper映射到一个db。没有必要在一个项目中为一个数据库保留太多SQLiteOpenHelper对象。你可以这样做:

// 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();
    }
}

接下来是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;
    }
}

这里我使用静态和同步方法来锁定方法,并在每个方法中添加计算。当调用getWriteableDatabse()方法时,我将增加连接数,否则我会减少它。当连接数为0时,我关闭数据库连接池。我认为这可能是安全的,也关闭了连接。 (注意,关闭Helper类也将关闭SQLiteDatabse对象。您可以参考源代码。)

希望它有效!