Подтвердить что ты не робот

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)

И затем я закрываю курсор и db. В этом случае ошибка попала в строку:

cursor.moveToFirst();

Я не понимаю, почему ошибка говорит о том, что db закрывается, если я вызываю this.getReadableDatabase() раньше. Пожалуйста Поддержи! Спасибо:)

4b9b3361

Ответ 1

Удалить

db.close();

Если вы попробуете другую операцию после закрытия базы данных, она предоставит вам это исключение.

В документации говорится:

Освобождает ссылку на объект, закрывает объект...

Кроме того, проверьте Закрытое исключение Android Sq Lite о комментарии разработчика Android Framework, в котором говорится, что закрыть соединение с базой данных не требуется.

Ответ 2

В настоящее время у меня такая же проблема. Выбрав 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, который он хранит, а затем поток Сначала завершил свою работу и вызвал SQLiteDatabase.close(), теперь поток объектов SQLiteDatabase B имеет закрытый, поэтому любые последующие вызовы операций db или вызовы метода курсора будут вызывать исключение.

Ответ 3

У меня такая же проблема, не удалось ее исправить. Я нашел возможную подсказку: У меня есть поток синхронизации, который работает все время:

    Item ii = dbHelper.popPendingUpload();
    if (ii != null)
            upload(ii);

И внутри DBHelper

public Item popPendingUpload() {

    SQLiteDatabase db = getReadableDatabase();
    Cursor res = db
            .rawQuery("SELECT * FROM items WHERE state = 0 LIMIT 1",
                    new String[] {});
    boolean hasNext = res.moveToFirst();
    Item ii = null;
    if (hasNext) {
        ii = //load item
    }
    db.close();
    return ii;
}

Ошибка также появляется в вызове метода moveToFirst(). Поскольку поток выдает элементы в бесконечном цикле, первый раз он работает нормально, второй раз появляется ошибка. Интересная часть состоит в том, что если я поставлю точку останова и пройду через код, ошибка больше не будет отображаться. Я тестирую на реальном устройстве с помощью Android 4.1.

Я знаю, это не ответ, но это может помочь. Я буду продолжать тестирование.

Ответ 4

//close database after cursor is closed like:

if(cursor.getCount() != 0){

    while(cursor.moveToNext()){
      //do operation
    }
}

cursor.close();
database.close();

Ответ 5

Возможно, вы закрываете базу данных до доступа к базе данных из своего приложения.

Вам нужно изменить getProfile() на

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

  try {
    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();
  finally {
    db.close();
  }
  return profile;
}

Ответ 6

У меня есть ошибка, как у вас, здесь мой код:

  try {
                        String sql = "SELECT * FROM "+DB_TABLEDOWNLOAD;
                        Cursor cursor = db.rawQuery(sql, null);
                        //空双引号为原表没有的字段
                        String temp = "";
                        int existIconPath = cursor.getColumnIndex("iconPath");
                        int existAudioID = cursor.getColumnIndex("audioID");

                        if (existIconPath == -1 && existAudioID == -1){
                            temp = "url, downed,total,path,name, audioTitle, audioFileID,\"\",\"\"";
                        }else if (existIconPath == -1 && existAudioID != -1){//iconPath不存在
                            temp = "url, downed,total,path,name, audioTitle, audioFileID,\"\",audioID";
                        }else if (existIconPath != -1 && existAudioID == -1){//audioID不存在
                            temp = "url, downed,total,path,name, audioTitle, audioFileID,iconPath,\"\"";
                        }else {
                            return;
                        }

                        db.beginTransaction();
                        String tempTableName = "_temp_"+DB_TABLEDOWNLOAD;
                        String sqlCreateTemp = " ALTER TABLE "+DB_TABLEDOWNLOAD+" RENAME TO "+tempTableName+";";
                        db.execSQL(sqlCreateTemp);
                      
                        final String TB_TESTPAPERINFO_CREATE = "Create  TABLE IF NOT EXISTS "
                                + DB_TABLEDOWNLOAD
                                + "(url TEXT, downed TEXT,total TEXT,path TEXT,name TEXT, audioTitle TEXT, audioFileID TEXT,iconPath TEXT, audioID TEXT);";
                        db.execSQL(TB_TESTPAPERINFO_CREATE);

                        String sqlBackupData = "INSERT INTO "+DB_TABLEDOWNLOAD+" SELECT "+temp+" FROM "+tempTableName+";";
                        db.execSQL(sqlBackupData);
                        String sqlDrop = "DROP TABLE IF EXISTS '"+tempTableName+"';";
                        db.execSQL(sqlDrop);
                        db.setTransactionSuccessful();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally{
                        db.endTransaction();
                    }