Recuerde el problema de cierre de SQLiteDatabase una vez

Un día se encontró una anomalía en el proyecto de la empresa.

java.lang.IllegalStateException: intento de volver a abrir un objeto ya cerrado

Más tarde, después de la investigación, se encontró que todas las operaciones de base de datos en el proyecto obtendrán el objeto de base de datos getWritableDatabase una vez antes y cerrarán la base de datos después de que se complete la operación, así:

    public synchronized void insertSelfGroup(SelfGroup.Group group){
    
    
        if(group == null){
    
    
            return;
        }
        //获取数据库
        SQLiteDatabase db = getWritableDatabase();
        if (db != null) {
    
    
            try {
    
    
                db.beginTransaction();
                ContentValues cv = group2CV(group);
                db.insert(GROUP_TABLE, null, cv);
                db.setTransactionSuccessful();
            } catch (Exception e) {
    
    
                e.printStackTrace();
            } finally {
    
    
                db.endTransaction();
                //关闭数据库
                db.close();
            }
        }
    }

Normalmente, no hay problema con esto, pero si dos subprocesos operan al mismo tiempo, aparecerá el error anterior. Por ejemplo, el subproceso A llama al método de cambio, y luego el subproceso B también llama a este método. Sabemos que el objeto de base de datos obtenido por el mismo objeto SQLiteOpenHelper es el mismo. Si el subproceso A termina de ejecutarse primero y ejecuta cerrar, la base de datos se ha cerrado en este momento, y el subproceso B aún no ha terminado de ejecutarse, y se informará un error.

Sabiendo que el motivo es el cierre de la base de datos, ¿cómo solucionarlo?

Busqué en Internet sobre el problema de cerrar la base de datos SQLite y descubrí que la mayoría de las personas sugieren no cerrar la base de datos o cerrar la base de datos al salir de la aplicación, pero otra forma de decir es que si la base de datos no se cierra durante mucho tiempo, ocurrirá la siguiente excepción:

Leak found
Caused by: java.lang.IllegalStateException: SQLiteDatabase created and never closed

Y sugieren usar un contador, que es +1 al adquirir un objeto de base de datos y -1 al cerrar. Si el valor del contador es 0 al cerrar, significa que la base de datos está cerrada cuando no hay operación de base de datos. El uso simple es el siguiente:

public class DatabaseManager{
    
    

    private AtomicInteger mOpenCounter = new AtomicInteger();

    private static DatabaseManager instance;
    private static SQLiteOpenHelper mDatabaseHelper;
    private SQLiteDatabase mDatabase;

    public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
    
    
        if (instance == null) {
    
    
            instance = new DatabaseManager();
            mDatabaseHelper = helper;
        }
    }

    public static synchronized DatabaseManager getInstance() {
    
    
        if (instance == null) {
    
    
            throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
                    " is not initialized, call initializeInstance(..) method first.");
        }

        return instance;
    }

    public synchronized SQLiteDatabase openDatabase() {
    
    
        if(mOpenCounter.incrementAndGet() == 1) {
    
    
            // Opening new database
            mDatabase = mDatabaseHelper.getWritableDatabase();
        }
        return mDatabase;
    }

    public synchronized void closeDatabase() {
    
    
        if(mOpenCounter.decrementAndGet() == 0) {
    
    
            // Closing database
            mDatabase.close();

        }
    }}

Cuando originalmente pensé que este método debería ser la solución óptima, encontré una descripción de SQLite en el documento de Google:
inserte la descripción de la imagen aquí
Ahora estoy en un lío, ¿cuál es la forma más razonable de hacerlo?
Así que eché un vistazo a cómo lo hacen algunos marcos de bases de datos conocidos. Primero, miré a Litepal y descubrí que no cerraba la base de datos. Solo cerraba la base de datos cuando se eliminaba. Miré a GreenDao y descubrí que no cerraba la base de datos. No hay ninguna operación para cerrar la base de datos en mo, y el documento oficial también da esa sugerencia:
inserte la descripción de la imagen aquí

La conclusión tentativa final es que no hay necesidad de cerrar la base de datos , y la actualizaré si encuentro algún problema más adelante.

Supongo que te gusta

Origin blog.csdn.net/shanshui911587154/article/details/122562408
Recomendado
Clasificación