13

我正在使用 sqlite db 并使用 Alex LockWood 的一些代码正确管理您的 SQLite 数据库

它工作得很好,但有时我得到了错误"java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed." 这是完整的错误:

02-20 16:37:21.385: W/dalvikvm(25730): threadid=13: thread exiting with uncaught exception (group=0x41c122a0)
02-20 16:37:21.390: E/AndroidRuntime(25730): FATAL EXCEPTION: Timer-0
02-20 16:37:21.390: E/AndroidRuntime(25730): java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
02-20 16:37:21.390: E/AndroidRuntime(25730):    at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:963)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:678)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:349)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:143)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at com.uit.pokemon.DatabaseHandler.getStadiumStatusById(DatabaseHandler.java:533)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at playground.RoomActivity.checkTable(RoomActivity.java:276)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at playground.RoomActivity$6.run(RoomActivity.java:321)
02-20 16:37:21.390: E/AndroidRuntime(25730):    at java.util.Timer$TimerImpl.run(Timer.java:284)
02-20 16:37:21.460: I/timertask cancel(25730): canceled

这是导致错误的代码:

public int getStadiumStatusById(int dataStadiumId){
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cur = db.rawQuery("SELECT " + keyStadiumId + " as _id, "
                + keyRoomName + ", " + keyP1Name + ", " + keyP1PokemonName
                + ", " + keyP1PokemonLevel + ", " + keyP1PokemonHp + ", "
                + keyP2Name + ", " + keyP2PokemonName + ", "
                + keyP2PokemonLevel + ", " + keyP2PokemonHp + ", "
                + keyTimeCreate + ", " + keyStadiumStatus + " from "
                + tbl_stadium + " WHERE " + keyStadiumId + " = " + "'"
                + dataStadiumId + "'", new String[] {});

        int stadiumStatus = 0;
        if(cur.getCount()>0)
        {
        cur.moveToFirst();
        stadiumStatus = cur.getInt(11);
        }
        db.close();
        cur.close();
        return stadiumStatus;
    }

我用谷歌搜索了好几个小时,但没有结果。请帮我修复它。任何帮助将不胜感激。谢谢!

4

6 回答 6

1

在您使用的代码中:

db.close();
cur.close();

最好的做法是先关闭游标,然后再关闭数据库,因为一旦调用db.close(),它会使数据库冻结 n 关闭,其对应的游标无效。试试这个改变它会起作用。

将其替换为:

cur.close();
db.close();
于 2016-06-17T11:36:33.173 回答
0

我也在处理这个问题。我知道原因,很想听听专家对此的看法。我做了很多假设,并得出了一些没有证据支持的结论......

我认为异常是在“返回体育场状态”行中引发的。上面几行,您将此变量分配给 Cursor 的成员。我相信您实际上是在指定名称 StadiumStatus 以指向仅存在于游标内的 int 变量。另一种可能性(这里是逻辑的巨大飞跃)是 Cursor.getInt() 返回的项目实际上是指向开放数据库中的项目(方法?)的指针(它驻留在内存中,因为它是开放的。)无论哪种方式,当您关闭游标和/或数据库然后尝试返回 StadiumStatus 时,int 指向游标中的地址由游标传递的地址,尝试跟随它,并在关闭的游标或关闭的数据库(一个其中是您从中提取的“数据池”。)

如果我是对的,我认为最好的解决办法是替换:

“体育场状态 = cur.getInt(11);”

和:

“体育场状态=新整数(cur.getInt(11));”

从而在内存中创建一个新的 Integer,vm 可以轻松地将其转换为 int,并且仅依赖于其传统的可访问范围。

这个答案有意义吗?我确信提问者早就解决了这个问题,但我很想能够说我回答了 Stack Overflow 上的一个问题(或者被告知我为什么错了,并且对游标和数据库有更好的理解)。

编辑:这些答案暗示我可能是对的:
Android错误:无法执行此操作,因为连接池已关闭
数据库关闭后光标是否仍然存在?
在第二个答案中,享有盛誉的用户 DeeV 称 Cursors 为“持久连接”,暗示它不是从数据库返回值的简单集合。

于 2014-02-28T08:37:58.210 回答
0

我遇到了这个问题,在这里解决了java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed。就我而言,我分析了android的数据库框架。mime 的真正原因是我在许多用于保存和查询数据的存储对象中使用 SQLiteDatabase。由于 SQLiteOpenHelper 是单例的,因此 SQLiteDatabase 也是单例的。即使我在一个商店中添加了同步,它仍然在另一个商店中解锁。所以,如果我忘记在一个地方删除 SQLiteDatabase.close() ,它将导致 SQLiteConnectionPool 关闭。此外,我还添加了一些释放 SQLite 连接的方法。希望能帮助到你。

于 2018-02-07T13:42:19.570 回答
0

我发现在多线程中使用数据库时也会发生此异常。所以最好在和synchronized之间db = helper.getXXXDatabase()加上db.close()

于 2017-03-02T13:57:21.700 回答
0

类打开的数据库在SQLiteOpenHelper类的生命周期内保持打开状态。

所以不需要打开和关闭数据库。实际上如果在多个线程上使用,就会出错。

我的应用程序已经有一段时间没有数据库错误了,我有一个助手类。这需要是一个单例,所以 SqliteDatabase 的不同实例不要尝试同时修改文件。

此外,我曾经遇到的一些崩溃表明游标和查询都可以调用 sqlite 查询,因此允许对数据库进行并发读写访问是没有意义的。

出于这个原因,我向助手添加了一个读/写锁,并使用这种模式......

    public static class MyDbHelper extends SQLiteOpenHelper {
        private MyDbHelper (Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
        public static MyDbHelper mInstance;
        private static Object mObj = new Object();
        public static MyDbHelper getInstance( Context context ){
            synchronized (mObj ){
                if( mInstance == null ){
                    mInstance = new MyDbHelper ( context );
                }
            }
            return mInstance;
        }
        private ReentrantReadWriteLock mLock = new ReentrantReadWriteLock();
        public Lock readLock() {
            return mLock.readLock();
        }
        public Lock writeLock() {
            return mLock.writeLock();
        }

使用类是这样的......

    MyStorageContract.MyDbHelper helper = MyStorageContract.MyDbHelper.getInstance(this);
    SQLiteDatabase db = helper.getReadableDatabase();
    helper.readLock().lock();
    try {
        String[] columns = {
                MyStorageContract.Libraries.COLUMN_NAME_LIBRARY_ID,
                MyStorageContract.Libraries.COLUMN_NAME_LIBRARY_DIR,
                MyStorageContract.Libraries.COLUMN_NAME_LIBRARY_SOMETHING,
        };
        String result = null;
        Cursor c = db.query(MyStorageContract.Libraries.TABLE_NAME, columns, null, null, null, null, null, "1");
        int idxDir = c.getColumnIndex(MyStorageContract.Libraries.COLUMN_NAME_LIBRARY_DIR);
        int idxRoot = c.getColumnIndex(MyStorageContract.Libraries.COLUMN_NAME_LIBRARY_SOMETHING);
        int idxId = c.getColumnIndex(MyStorageContract.Libraries.COLUMN_NAME_LIBRARY_ID);
        for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
            result = c.getString(idxDir);
        }
        c.close();
        return result;
    }
    finally {
        helper.readLock().unlock();
    }
于 2018-01-31T22:41:28.063 回答
-6

称呼

db.open()

在这一行之后:

SQLiteDatabase db = this.getReadableDatabase();

但是,我个人不知道具体情况如何this.getReadableDatabase(),但我会制作自己的数据库适配器。有关详细信息,请参阅此链接:http ://www.vogella.com/articles/AndroidSQLite/article.html

于 2013-09-27T05:28:02.723 回答