Java – sqlitedatabase multi thread locking mode

I use this class to manage connections to the underlying SQLite database

public class BasicDataSource {

    protected DatabaseHandler dbHelper;
    protected volatile sqliteDatabase readable_database;
    protected volatile sqliteDatabase writable_database;
    protected Object read_lock = new Object();
    protected Object write_lock = new Object();
    protected Context context;

    protected BasicDataSource(Context ctx) {
        dbHelper = DatabaseHandler.getInstance(ctx);
        getReadableDatabase();
        dbHelper.onCreate(getWritableDatabase());
        this.context = ctx;
    }

    public synchronized void close() {
        dbHelper.close();
    }

    protected void closeInsertHelpers(InsertHelper... helpers) {
        for (InsertHelper ih : helpers) {
            if (ih != null)
                ih.close();
        }
    }

    protected sqliteDatabase getReadableDatabase() {
        synchronized (read_lock) {
            if (readable_database == null || !readable_database.isopen()) {
                readable_database = dbHelper.getReadableDatabase();
            }
            return readable_database;
        }
    }

    protected sqliteDatabase getWritableDatabase() {
        synchronized (write_lock) {
            if (writable_database == null || !writable_database.isopen()) {
                writable_database = dbHelper.getWritableDatabase();
            }
            return writable_database;
        }
    }

    protected synchronized void open() throws sqlException {
        getReadableDatabase();
        getWritableDatabase();
    }
}

It contains two locks, one for reading and the second for writing But I occasionally get such an exception:

java.lang.RuntimeException: An error occured while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:299)
        at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
        at java.util.concurrent.FutureTask.run(FutureTask.java:137)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
        at java.lang.Thread.run(Thread.java:856)
Caused by: android.database.sqlite.sqliteDatabaseLockedException: database is locked (code 5):,while compiling: PRAGMA journal_mode
        at android.database.sqlite.sqliteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.sqliteConnection.acquirePreparedStatement(sqliteConnection.java:882)
        at android.database.sqlite.sqliteConnection.executeForString(sqliteConnection.java:627)
        at android.database.sqlite.sqliteConnection.setJournalMode(sqliteConnection.java:313)
        at android.database.sqlite.sqliteConnection.setWalModeFromConfiguration(sqliteConnection.java:287)
        at android.database.sqlite.sqliteConnection.open(sqliteConnection.java:215)
        at android.database.sqlite.sqliteConnection.open(sqliteConnection.java:193)
        at android.database.sqlite.sqliteConnectionPool.openConnectionLocked(sqliteConnectionPool.java:463)
        at android.database.sqlite.sqliteConnectionPool.open(sqliteConnectionPool.java:185)
        at android.database.sqlite.sqliteConnectionPool.open(sqliteConnectionPool.java:177)
        at android.database.sqlite.sqliteDatabase.openInner(sqliteDatabase.java:804)
        at android.database.sqlite.sqliteDatabase.open(sqliteDatabase.java:789)
        at android.database.sqlite.sqliteDatabase.openDatabase(sqliteDatabase.java:694)
        at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:804)
        at android.content.Contextwrapper.openOrCreateDatabase(Contextwrapper.java:221)
        at android.database.sqlite.sqliteOpenHelper.getDatabaseLocked(sqliteOpenHelper.java:224)
        at android.database.sqlite.sqliteOpenHelper.getWritableDatabase(sqliteOpenHelper.java:164)
        at com.mycompany.myapplication.sql.BasicDataSource.getWritableDatabase(BasicDataSource.java:57)
        at com.mycompany.myapplication.sql.datasources.someDataSource.fillUpDatabaseMethod(SomeDataSource.java:264)
        at com.mycompany.myapplication.sql.datasources.someDataSource.renewCacheMethod(SomeDataSource.java:560)
        at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:315)
        at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:1)
        at android.os.AsyncTask$2.call(AsyncTask.java:287)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
        ... 4 more
android.database.sqlite.sqliteDatabaseLockedException: database is locked (code 5):,while compiling: PRAGMA journal_mode
        at android.database.sqlite.sqliteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.sqliteConnection.acquirePreparedStatement(sqliteConnection.java:882)
        at android.database.sqlite.sqliteConnection.executeForString(sqliteConnection.java:627)
        at android.database.sqlite.sqliteConnection.setJournalMode(sqliteConnection.java:313)
        at android.database.sqlite.sqliteConnection.setWalModeFromConfiguration(sqliteConnection.java:287)
        at android.database.sqlite.sqliteConnection.open(sqliteConnection.java:215)
        at android.database.sqlite.sqliteConnection.open(sqliteConnection.java:193)
        at android.database.sqlite.sqliteConnectionPool.openConnectionLocked(sqliteConnectionPool.java:463)
        at android.database.sqlite.sqliteConnectionPool.open(sqliteConnectionPool.java:185)
        at android.database.sqlite.sqliteConnectionPool.open(sqliteConnectionPool.java:177)
        at android.database.sqlite.sqliteDatabase.openInner(sqliteDatabase.java:804)
        at android.database.sqlite.sqliteDatabase.open(sqliteDatabase.java:789)
        at android.database.sqlite.sqliteDatabase.openDatabase(sqliteDatabase.java:694)
        at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:804)
        at android.content.Contextwrapper.openOrCreateDatabase(Contextwrapper.java:221)
        at android.database.sqlite.sqliteOpenHelper.getDatabaseLocked(sqliteOpenHelper.java:224)
        at android.database.sqlite.sqliteOpenHelper.getWritableDatabase(sqliteOpenHelper.java:164)
        at com.mycompany.myapplication.sql.BasicDataSource.getWritableDatabase(BasicDataSource.java:57)
        at com.mycompany.myapplication.sql.datasources.someDataSource.fillUpDatabaseMethod(SomeDataSource.java:264)
        at com.mycompany.myapplication.sql.datasources.someDataSource.renewCacheMethod(SomeDataSource.java:560)
        at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:315)
        at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:1)
        at android.os.AsyncTask$2.call(AsyncTask.java:287)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
        at java.util.concurrent.FutureTask.run(FutureTask.java:137)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
        at java.lang.Thread.run(Thread.java:856)

This means that when trying to get a lock in getwritabledatabase, the database is locked in some way

My sqliteopenhelper is in singleton mode, and datasources only uses basic datasource as the parent class

What improvements can be made to avoid sqlitedatabaselockedexception in the displayed code?

Solution

In SQLite, you can have as many readers as you want, but any writer will block all other readers and writers

You must use a single lock for readers and writers

Please note that the lock must remain as long as you actually access the database

If you want to support multiple readers, use a lock that implements readwritelock, such as reentrantreadwritelock Something like this:

class MyData {
    private final reentrantreadwritelock rwl = new reentrantreadwritelock();
    private final Lock r = rwl.readLock();
    private final Lock w = rwl.writeLock();

    public Data ReadSomething(int id) {
        r.lock();
        try {
            Cursor c = readableDatabase.query(...);
            return c.getString(0);
        } finally {
            r.unlock();
        }
    }

    public void ChangeSomething(int id,int value) {
        w.lock();
        try {
            writeableDatabase.update(...);
        } finally {
            w.unlock();
        }
    }
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>