SQLite
 sql >> Baza danych >  >> RDS >> SQLite

Problem z pamięcią SQLite przy podejściu singleton

Jeśli otrzymujesz komunikat wskazujący, że otwartych jest zbyt wiele plików, przyczyną może być to, że jest zbyt wiele otwartych kursorów.

Jednak zwrócona wiadomość może nie zawsze być taka sama i prawdopodobnie jest specyficzna dla wywoływanego zadania/połączenia.

W tym przypadku komunikat to (unable to open database file (code 2062)) , jeszcze w innym przypadku (z SELECT wiadomość była unable to open database file (code 14) ). SQLite nie może otworzyć pliku bazy danych (kod 14) przy częstym zapytaniu „SELECT”.

Powyższy link wskazuje również na post, który napisałem, co dość wyraźnie pokazuje, że utworzenie kursora skutkuje otwarciem pliku (lub plików).

Przykładem było przechodzenie przez około 500 wierszy i dla każdego wiersza tworzył/odtwarzał 3 kursory dla każdego wiersza (więc potencjalnie 1500+ kursorów, mimo że używano tylko 4 obiektów kursora).

Początkowo zamykało tylko 3 kursory na końcu (ostatni wiersz rodzica wszystkich), co spowodowało unable to open database File (code 14) . Zamknięcie 3 kursorów dla każdej iteracji rozwiązało problem.

Kod, który się nie powiódł, to :-

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

Podczas gdy stały kod to :-

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

Mam tendencję do przestrzegania następującej zasady/praktyki:-

  • Jeśli po prostu otrzymujesz wynik, np. pobierając liczbę wierszy, zamknij Kursor w metodzie.

  • Jeśli używasz Kursora do wyświetlania np. ListView, a następnie zamknij kursor w onDestroy aktywności metoda.

  • Jeśli używasz Kursora do czegoś, co nazywam bardziej złożonym przetwarzaniem, np. usuwanie wierszy z bazowymi referencjami, a następnie zamykanie kursorów, gdy tylko skończą, w ramach pętli przetwarzania.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Unia SQLite

  2. Grupuj SQLite według/licz godziny, dni, tygodnie, rok

  3. 2 sposoby zwracania wartości nienumerycznych w SQLite

  4. Android Room:jak przenieść zmianę nazwy kolumny?

  5. Jak działa RandomBlob() w SQLite