web-dev-qa-db-ja.com

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()を呼び出している場合、エラーが原因でデータベースが閉じられていると表示される理由はわかりません。サポートしてください!ありがとうございました :)

53
Ferran Negre

削除する

db.close();

データベースを閉じた後に別の操作を試みると、その例外が発生します。

ドキュメント の意味:

オブジェクトへの参照を解放し、オブジェクトを閉じます...

また、 Android Sq Liteは例外を閉じました Androidデータベース接続を閉じる必要はないというフレームワークエンジニアからのコメントについて)をチェックしてください。

77
AmmarCSE

現在同じ問題があります。 db.close()を削除することで問題は解決しますが、この問題はマルチスレッドが原因であると思います。これが私の研究です。

SQLiteOpenHelperは、SQLiteDatabaseへの参照を保持します。getReadableDatabase()またはgetWritableDatabase()が呼び出されると、SQLiteDatabaseがclosedまたはnull、新しいSQLiteDatabaseオブジェクトが作成されます。 getメソッド内では、コードは同期ブロックで保護されていることに注意してください。

SQLiteDatabaseはSQLiteClosableのサブクラスです。 SQLiteClosableは、参照カウントスキームを実装します。

  • 最初に作成されたとき、カウントは1です。

  • データベース操作メソッドが実行されると(挿入、クエリなど)、カウントが増加し、メソッドが終了するとカウントが減少します。ただし、カーソル操作は参照カウントによって保護されません。

  • カウントが0に減少すると、接続プールが閉じられ、メンバーSQLiteConnectionPoolオブジェクトがnullに設定され、SQLiteDatabaseはclosedになります。

  • SQLiteDatabase.close()は、カウントを1減らします。

したがって、シングルスレッドスキームを使用している場合、SQLiteOpenHelperが再作成するだけなので、SQLiteDatabaseを閉じることは問題ありません。

マルチスレッドを実行すると、問題が発生します。スレッドAとスレッドBの両方がgetReadableDatabase()を呼び出し、SQLiteOpenHelperが保持するSQLiteDatabaseを返し、次にスレッドAが最初にその操作を完了してSQLiteDatabase.close()を呼び出し、SQLiteDatabaseオブジェクトスレッドBがclosedしたがって、後続のdb操作呼び出しまたはカーソルメソッド呼び出しは例外をスローします。

19
handhand
//close database after cursor is closed like:

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

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

cursor.close();
database.close();
3
Mohammad nabil

私は同じ問題を抱えていますが、それを修正することができませんでした。私は可能な手がかりを見つけました:常に実行されている同期スレッドがあります:

    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()メソッドの呼び出しでも表示されます。スレッドは無限ループでアイテムをポップアウトするため、最初に正常に機能するとき、2回目にエラーが表示されます。興味深い部分は、ブレークポイントを設定してコードをステップスルーすると、エラーが表示されなくなることです。 Android 4.1。を使用して、実際のデバイスでテストしています。

答えではありませんが、役立つかもしれません。テストを続けます。

3
Jason Oviedo

これは、Android getApplicationContext()を使用したルームデータベースのアーキテクチャ初期化の単純なエラーです。したがって、いずれかのアクティビティで閉じた場合、他のユーザーはその例外をスローします。

基本的に、例外をスローするアクティビティだけをチェックするのではなく、db.close()のすべてのアクティビティをチェックします

1
E-max

私はあなたのようなエラーがあります、ここに私のコード:

  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();
                    }

Db.beginTransaction()の前にreturnを使用し、beginTransactionの前に私のコードを返しますが、finallyでendTransactionを使用します。 beginTransactionおよびendTransactionを実行しない場合、例外が表示されます。

そのため、db.beginTransactionおよびendTransactionに関するコードを確認してください。

0
doordoor

たぶん、アプリからデータベースにアクセスする前にデータベースを閉じます。

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;
}
0
yaginier