SQLite
 sql >> Datenbank >  >> RDS >> SQLite

SQLite-Speicherproblem mit Singleton-Ansatz

Wenn Sie eine Meldung erhalten, dass zu viele Dateien geöffnet sind, kann dies daran liegen, dass noch zu viele Cursor geöffnet sind.

Die zurückgegebene Nachricht ist jedoch möglicherweise nicht immer dieselbe und ist wahrscheinlich spezifisch für die aufgerufene Aufgabe/Aufruf.

In diesem Fall lautete die Meldung (unable to open database file (code 2062)) , noch in einem anderen Fall (von einem SELECT war die Meldung unable to open database file (code 14) ). SQLite kann die Datenbankdatei (Code 14) bei häufiger „SELECT“-Abfrage nicht öffnen.

Der obige Link verweist auch auf einen von mir erstellten Beitrag, der ganz klar zeigt, dass das Erstellen eines Cursors dazu führt, dass eine Datei (oder Dateien) geöffnet werden.

Das Beispiel hat ungefähr 500 Zeilen durchlaufen und für jede Zeile 3 Cursor für jede Zeile erstellt/neu erstellt (also möglicherweise 1500+ Cursor, obwohl nur 4 Cursorobjekte verwendet wurden).

Anfangs wurden nur die 3 Cursor am Ende geschlossen (letzte Zeile des übergeordneten Elements von allen), was dazu führte, dass unable to open database File (code 14) . Das Schließen der 3 Cursor für jede Iteration löste das Problem.

Der fehlgeschlagene Code war:-

        SQLiteDatabase db = getWritableDatabase();
        Cursor shoplistcursor = getAllRowsFromTable(SHOPLIST_TABLE_NAME);
        Cursor productcsr;
        Cursor aislecsr;
        Cursor prdusecsr;
        while(shoplistcursor.moveToNext()) {
            productcsr = getProductFromProductId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
            aislecsr = getAisleFromAisleId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)));
            prdusecsr = getProductUsage(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)),
                    shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
            if (productcsr.getCount() < 1 | aislecsr.getCount() < 1 | prdusecsr.getCount() < 1) {
                deleteShopListEntry(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_ID)));
            } 
            if(shoplistcursor.isLast()) {
                prdusecsr.close();
                aislecsr.close();
                productcsr.close();
            }
        }
        shoplistcursor.close();
        db.close();
}

Während der feste Code :-

war
        SQLiteDatabase db = getWritableDatabase();
        Cursor shoplistcursor = getAllRowsFromTable(SHOPLIST_TABLE_NAME);
        Cursor productcsr;
        Cursor aislecsr;
        Cursor prdusecsr;
        while(shoplistcursor.moveToNext()) {
            productcsr = getProductFromProductId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
            aislecsr = getAisleFromAisleId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)));
            prdusecsr = getProductUsage(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)),
                    shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
            if (productcsr.getCount() < 1 | aislecsr.getCount() < 1 | prdusecsr.getCount() < 1) {
                productcsr.close();
                aislecsr.close();
                prdusecsr.close();
                deleteShopListEntry(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_ID)));
            } else {
                productcsr.close();
                aislecsr.close();
                prdusecsr.close();
            }
        }
        shoplistcursor.close();
        db.close();
    }

Ich neige dazu, jetzt der folgenden Regel/Praxis zu folgen:-

  • Wenn Sie nur das Ergebnis erhalten, z. Um die Anzahl der Zeilen zu erhalten, schließen Sie den Cursor in der Methode.

  • Wenn Sie den Cursor für eine Anzeige verwenden, z. a ListView, schließen Sie dann den Cursor im onDestroy der Aktivität Methode.

  • Wenn Sie den Cursor für eine, wie ich es nenne, komplexere Verarbeitung verwenden, z. Löschen von Zeilen mit zugrunde liegenden Referenzen und Schließen der Cursor, sobald sie fertig sind, innerhalb der Verarbeitungsschleife(n).