Android:无法执行此操作,因为连接池已关闭

新手上路,请多包涵

我正在通过 StackOverflow 阅读有关此问题的信息,但仍未找到解决方案。我注意到有时我的应用程序会抛出此错误:

    java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
        at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
        at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:599)
        at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
        at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
        ...

我有一个名为 DatabaseHelper.java 的文件,使用这种方法获取它的一个实例:

 public static DatabaseHelper getInstance(Context context) {
    if (mInstance == null) {
        mInstance = new DatabaseHelper(context.getApplicationContext());
    }
    return mInstance;
}

然后我有这样的方法(它在 cursor.moveToFirst() 行崩溃并出现该错误)。它几乎从不崩溃,但有时会崩溃。

 public Profile getProfile(long id) {
    SQLiteDatabase db = this.getReadableDatabase();

    String selectQuery = "SELECT * FROM " + TABLE_PROFILES + " WHERE " + KEY_PROFILES_ID + " = " + id;
    Cursor cursor = db.rawQuery(selectQuery, null);

    // looping through all rows and adding to list
    Profile profile = new Profile();
    if (cursor.moveToFirst()) {
        doWhatEver();
    }
    cursor.close();
    db.close();

    return profile;
}

就是这样,在我使用的所有方法中:

 SQLiteDatabase db = this.getReadableDatabase(); (or Writable)

然后我关闭游标和数据库。在这种情况下,错误在行中抛出:

 cursor.moveToFirst();

如果我之前调用 this.getReadableDatabase() ,我不明白为什么错误说数据库已关闭。请支持!谢谢 :)

原文由 Ferran Negre 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

消除

db.close();

如果你在关闭数据库后尝试另一个操作,它会给你那个异常。

文件 说:

释放对对象的引用, 关闭对象…

另外,查看 Android SQLite 关闭的异常,关于来自 Android Framework 工程师的评论,该评论指出没有必要关闭数据库连接,但这仅当它在 ContentProvider 中管理时。

原文由 AmmarCSE 发布,翻译遵循 CC BY-SA 4.0 许可协议

我目前有同样的问题。虽然删除 db.close() 为我解决了问题,但我认为问题是由多线程引起的。这是我的研究。

SQLiteOpenHelper holds a reference to SQLiteDatabase , when getReadableDatabase() or getWritableDatabase() called, it will return the reference, if the SQLiteDatabase 关闭 或为空,将创建一个新的 SQLiteDatabase 对象。请注意,在 get 方法内部,代码在同步块中得到保护。

SQLiteDatabaseSQLiteClosable 的子类。 SQLiteClosable 实现引用计数方案。

  • 首次创建时,计数为 1。

  • 当数据库操作方法运行时(如插入,查询),它会增加计数,当方法结束时减少计数。但是游标操作不受引用计数的保护。

  • 如果计数减少到0,连接池将被关闭并且一个成员 SQLiteConnectionPool 对象将被设置为null,现在 SQLiteDatabase关闭

  • SQLiteDatabase.close() 将计数减 1;

所以,如果你有一个单线程方案,关闭 SQLiteDatabase 会很好,因为 SQLiteOpenHelper 只会重新创建它。

如果你做多线程,那么你会遇到麻烦。假设线程 A 和线程 B 都调用 getReadableDatabase() ,并且 SQLiteOpenHelper 返回它持有的 SQLiteDatabase,然后线程 A 首先完成它的操作并调用 SQLiteDatabase.close() ,now-caf43039 SQLiteDatabase 对象线程 B 已 关闭,因此任何后续的数据库操作调用或游标方法调用都将引发异常。

原文由 handhand 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题