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

Fer*_*gre 54 java database sqlite singleton 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)
        ...
Run Code Online (Sandbox Code Playgroud)

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

public static DatabaseHelper getInstance(Context context) {
    if (mInstance == null) {
        mInstance = new DatabaseHelper(context.getApplicationContext());
    }
    return mInstance;
}
Run Code Online (Sandbox Code Playgroud)

然后我有像这样的方法(它在行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;
}
Run Code Online (Sandbox Code Playgroud)

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

SQLiteDatabase db = this.getReadableDatabase(); (or Writable)
Run Code Online (Sandbox Code Playgroud)

然后我关闭光标和数据库.在这种情况下,错误得到了线:

cursor.moveToFirst();
Run Code Online (Sandbox Code Playgroud)

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

Amm*_*CSE 80

去掉

db.close();
Run Code Online (Sandbox Code Playgroud)

如果在关闭数据库后尝试其他操作,它将为您提供该异常.

文件说:

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

另外,请查看 Android Sq Lite已关闭的异常,该异常是关于来自Android Framework工程师的评论,该评论表明关闭数据库连接不是必需的.

  • 删除db.close()为我修复了这个问题. (3认同)
  • 我在getInstance()中使用了同步字,正如它在博客中所示:http://touchlabblog.tumblr.com/post/24474750219/single-sqlite-connection然后我删除了所有的db.close().似乎工作正常.我也在这里阅读http://stackoverflow.com/questions/6608498/best-place-to-close-database-connection,这对于关闭它并不是必需的.无论如何,文件不清楚. (2认同)

han*_*and 20

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

SQLiteOpenHelper保存对SQLiteDatabase的引用,当调用getReadableDatabase()或getWritableDatabase()时,它将返回引用,如果SQLiteDatabase 关闭或为null,则将创建新的SQLiteDatabase对象.请注意,在get方法中,代码在同步块中受到保护.

SQLiteDatabase是SQLiteClosable的子类.SQLiteClosable实现了引用计数方案.

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

  • 当数据库操作方法运行时(如insert,query),它将增加计数,并在方法结束时减少计数.但是游标操作不受引用计数的保护.

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

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

因此,如果您有单线程方案,关闭SQLiteDatabase将没有问题,因为SQLiteOpenHelper将重新重新创建它.

如果你做多线程,那么你将遇到麻烦.假设线程A和线程B都调用getReadableDatabase(),并且SQLiteOpenHelper返回它保存的SQLiteDatabase,然后线程A首先完成其操作并调用SQLiteDatabase.close(),现在SQLiteDatabase对象线程B已关闭,因此任何后续的db操作调用或游标方法调用将抛出异常.

  • 那么第二种选择的解决方案是什么?(多线程) (5认同)
  • @HardikJoshi第二个解决方案是同步访问光标所在的代码。 (2认同)