programing

Android : 연결 풀이 닫 혔기 때문에이 작업을 수행 할 수 없습니다.

projobs 2021. 1. 14. 08:00
반응형

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

이전에 this.getReadableDatabase ()를 호출하면 오류가 db가 닫혔다 고 말하는 이유를 알 수 없습니다. 응원 해주세요! 감사합니다 :)


없애다

db.close();

데이터베이스를 닫은 후 다른 작업을 시도하면 해당 예외가 발생합니다.

문서는 말합니다 :

개체에 대한 참조를 해제하고 개체를 닫습니다.

또한 데이터베이스 연결을 닫을 필요가 없다는 Android Framework 엔지니어의 댓글에 대한 Android Sq Lite 마감 예외를 확인하십시오 .


나는 현재 같은 문제가 있습니다. db.close ()를 제거하면 문제가 해결되지만 다중 스레딩으로 인해 문제가 발생한다고 생각합니다. 여기 내 연구가 있습니다.

SQLiteOpenHelper는 SQLiteDatabase에 대한 참조를 보유하고 있으며, getReadableDatabase () 또는 getWritableDatabase ()가 호출되면 참조를 반환하고, SQLiteDatabase가 닫히 거나 null이면 새 SQLiteDatabase 객체가 생성됩니다. get 메서드 내에서 코드는 동기화 된 블록에서 보호됩니다.

SQLiteDatabase는 SQLiteClosable의 하위 클래스입니다. SQLiteClosable은 참조 계수 체계를 구현합니다.

  • 처음 생성 될 때 개수는 1입니다.

  • 데이터베이스 작업 메서드 (예 : 삽입, 쿼리)가 실행되면 개수가 증가하고 메서드가 종료되면 개수가 감소합니다. 그러나 커서 작업은 참조 카운트로 보호되지 않습니다.

  • 개수가 0으로 감소하면 연결 풀이 닫히고 멤버 SQLiteConnectionPool 개체가 null로 설정되며 이제 SQLiteDatabase가 닫힙니다 .

  • SQLiteDatabase.close ()는 카운트를 1 씩 줄입니다.

따라서 단일 스레드 구성표가있는 경우 SQLiteOpenHelper가 다시 생성하기 때문에 SQLiteDatabase를 닫는 것이 좋습니다.

다중 스레딩을 수행하면 문제가 발생합니다. 스레드 A와 스레드 B가 모두 getReadableDatabase ()를 호출하고 SQLiteOpenHelper가 보유한 SQLiteDatabase를 반환 한 다음 스레드 A가 먼저 작업을 완료하고 SQLiteDatabase.close ()를 호출한다고 가정합니다. 이제 SQLiteDatabase 객체 스레드 B가 닫혀 있으므로 모든 후속 db 작업 호출 또는 커서 메서드 호출은 예외를 throw합니다.


나는 같은 문제를 겪고 있으며 그것을 고칠 수 없었습니다. 가능한 단서를 찾았습니다. 항상 실행중인 동기화 스레드가 있습니다.

    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을 사용하는 실제 기기에서 테스트하고 있습니다.

답은 아니지만 도움이 될 수 있습니다. 계속 테스트하겠습니다.


//close database after cursor is closed like:

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

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

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

이것은 getApplicationContext ()를 사용하여 룸 데이터베이스의 Android 아키텍처 초기화에서 발생하는 간단한 오류입니다. 이는 얼마나 많은 활동이 인스턴스를 생성하는지에 관계없이 애플리케이션에 데이터베이스 참조 인스턴스가 하나 있음을 의미합니다. 따라서 어떤 활동에서든 닫으면 다른 사람들은 그 예외를 던질 것입니다.

본질적으로 예외를 발생시키는 활동을 확인하는 것이 아니라 db.close ()에 대한 모든 활동을 확인합니다.


Maybe you close the database before access to database from your app.

You have to edit getProfile() to

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

I have a error like yours ,here my code:

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

I use return before db.beginTransaction(),my code return before beginTransaction,but I endTransaction in finally . if you do not beginTransaction and endTransaction ,the exception will appear.

so check your code about the db.beginTransaction and endTransaction.

ReferenceURL : https://stackoverflow.com/questions/23293572/android-cannot-perform-this-operation-because-the-connection-pool-has-been-clos

반응형