Remember the closing problem of SQLiteDatabase once

One day an anomaly was found in the company's project

java.lang.IllegalStateException: attempt to re-open an already-closed object

Later, after investigation, it was found that all database operations in the project will obtain the database object getWritableDatabase once before , and close the database after the operation is completed, like this:

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

Normally, there is no problem with this, but if two threads operate at the same time, the above error will appear. For example, thread A calls the change method, and then thread B also calls this method. We know that the database object obtained by the same SQLiteOpenHelper object is the same. If thread A finishes executing first and executes close, the database has been closed at this time, and thread B has not yet finished executing, and an error will be reported.

Knowing that the reason is the shutdown of the database, how to solve it?

I searched on the Internet about the problem of closing the SQLite database and found that most people suggest not closing the database, or closing the database when exiting the App, but another way of saying is that if the database is not closed for a long time, the following exception will occur:

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

And they suggest using a counter, which is +1 when acquiring a database object, and -1 when closing. If the counter value is 0 when closing, it means that the database is closed when there is no database operation. The simple use is as follows:

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

        }
    }}

When I originally thought that this method should be the optimal solution, I found a description of SQLite in the Google document:
insert image description here
Now I am in a mess, what is the most reasonable way to do it?
So I took a look at how some well-known database frameworks do it. First, I looked at Litepal and found that it did not close the database. It only closed the database when it was deleted. I looked at GreenDao and found that it did not close the database. There is no operation to close the database in mo, and the official document also gives such a suggestion:
insert image description here

The final tentative conclusion is that there is no need to close the database , and I will update it if I find any problems later.

Guess you like

Origin blog.csdn.net/shanshui911587154/article/details/122562408