Android 数据库 - 无法执行此操作,因为连接池已关闭

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23387405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:05:07  来源:igfitidea点击:

Android database - Cannot perform this operation because the connection pool has been closed

androiddatabaseandroid-cursor

提问by qkx

I have strange problem with android database and cursors. Time to time (very rarely) happens, that I got crash report from customers. It's hard to find out why it crashes, as I have ~ 150 000 active users and maybe 1 report per week or so, so it's really some minor bug. Here is exception:

我有 android 数据库和游标的奇怪问题。时不时(很少)发生,我从客户那里得到崩溃报告。很难找出它崩溃的原因,因为我有大约 150 000 个活跃用户,每周可能会有 1 份报告,所以这确实是一些小错误。这是例外:

STACK_TRACE=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)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:144)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
at sk.mildev84.agendareminder.a.c.a(SourceFile:169)

Before every cursor "iterating and exploring" I use this code to make sure everything is ok:

在每个光标“迭代和探索”之前,我使用此代码来确保一切正常:

db = instance.getWritableDatabase();
cursor = db.rawQuery(selectQuery, null);

if (isCursorEmptyOrNotPrepared(cursor)) {
    ...
    }

private synchronized boolean isCursorEmptyOrNotPrepared(Cursor cursor) {
        if (cursor == null)
            return true;

        if (cursor.isClosed())
            return true;

        if (cursor.getCount() == 0) // HERE IT CRASHES
            return true;

        return false;
    }

And it falls at line:

它落在线:

if (cursor.getCount() == 0)

Anyone know why? I think, I am checking all possible exceptions and conditions...Why is my app crashing here?

有谁知道为什么?我想,我正在检查所有可能的异常和条件......为什么我的应用程序在这里崩溃?

PS: All database methods are synchronized and I am correctly opening and closing database/cursors in all cases, I checked it many times.

PS:所有数据库方法都是同步的,我在所有情况下都正确打开和关闭数据库/游标,我检查了很多次。

回答by Giru Bhai

Problem
If you try another operation after closing the database, it will give you that exception.Because db.close();releases a reference to the object, closing the object if the last reference was released.

Solution
Keep a single SQLiteOpenHelperinstance(Singleton) in a static context. Do lazy initialization, and synchronizethat method. Such as

问题
如果您在关闭数据库后尝试另一个操作,它会给您那个异常。因为db.close();释放对对象的引用,如果最后一个引用被释放,则关闭对象。

解决方案在静态上下文中
保留单个SQLiteOpenHelper实例 ( Singleton)。做懒惰初始化,和synchronize那个方法。如

public class DatabaseHelper
{
    private static DatabaseHelper instance;

    public static synchronized DatabaseHelper getInstance(Context context)
    {
        if (instance == null)
            instance = new DatabaseHelper(context);

        return instance;
    }
//Other stuff... 
}

And you don't have to close it? When the app shuts down, it'll let go of the file reference, if its even holding on to it.
i.e. You should not close the DB since it will be used again in the next call. So Just remove

而且您不必关闭它?当应用程序关闭时,它会释放文件引用,如果它甚至保留它
即您不应该关闭数据库,因为它将在下一次调用中再次使用。所以只需删除

db.close();

For more info See at Single SQLite connection

有关更多信息,请参阅单个 SQLite 连接

回答by Verdigrass

The problem is clear that

问题很明显

SQLiteCursor cannot perform 'getCount' operation because the connection pool has been closed

SQLiteCursor 无法执行“getCount”操作,因为连接池已关闭

To avoid IllegalStateException, we may keep the database open all the time if that is appropriate. In other situations we need to check the statusbefore trying getCount.

为避免 IllegalStateException,如果合适,我们可能会一直保持数据库打开。在其他情况下,我们需要在尝试 getCount 之前检查状态

My experience is as follows:

我的经验如下:

Defective Code:

有缺陷的代码:

SOLiteOpenHelper helper = new SOLiteOpenHelper(context);
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor = db.query(...);
if (cursor != null) {
    cursor.getCount(); // HERE IT CRASHES
}

Perfect Code:

完美代码:

SOLiteOpenHelper helper = new SOLiteOpenHelper(context);
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor = db.query(...);
if (cursor != null && db.isOpen()) {
    cursor.getCount(); // OK!
}

回答by Gary Wong

You just remove Remove db.close()

您只需删除 Remove db.close()

回答by Sherry

I had this problem too. my SQLiteOpenHelper class was Singleton as well as closing the db after each CRUD operation. After I make my methods(CRUD) synchronized in my SQLiteOpenHelper class, I didn't get error any more :)

我也有这个问题。我的 SQLiteOpenHelper 类是 Singleton 以及在每个 CRUD 操作后关闭数据库。在我的 SQLiteOpenHelper 类中同步我的方法(CRUD)后,我没有再收到错误:)

回答by Lokesh Tiwari

Same problem occured to me, so after reading explanationI removed
db.close();
from
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
and
public int delete(Uri uri, String selection, String[] selectionArgs)
method of ContentProvider
No need of db.close() as ContentProvider itself take care of closing of database.

同样的问题发生在我身上,所以在阅读解释后,
db.close();
从ContentProvider
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)

public int delete(Uri uri, String selection, String[] selectionArgs)
方法中删除了
不需要 db.close() 因为 ContentProvider 本身负责关闭数据库。