Android threading and database locking

后端 未结 7 1756
夕颜
夕颜 2020-12-07 10:31

We are using AsyncTasks to access database tables and cursors.

Unfortunately we are seeing occasional exceptions regarding the database being locked.

7条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-07 11:06

    Before some code, let's resume some of the approachs:

    • Semaphores: by far the best solution presented. It goes in the heart of the problem: resource sharing! It will treat the locking of the database access, avoiding conflicts (database is locked).

    • Java synchronization: A kind of semaphore implementation, but less sofisticated. Using synchronized you will not easily solve some cases involving transactions.

    • ContentProvider: implement ContentProvider solve the problem only for some cases (or sweep the problem under the carpet). You'll yet face the same issues. The difference is that ContentProvider pattern will guide you to not make some commom mistakes when accessing Sqlite database. The ContentProvider docs says: "You don't need a provider to use an SQLite database if the use is entirely within your own application."

    • Almost mandatory: keep db instances local, call close() on the db in the same method in which it's opened using finally statements, close() on the cursors using finally statements, etc are almost mandatory to avoid problems using Sqlite.

    Let's show an example of the semaphore solution presented by Moss, which I took from CL. and improoved to cover transactions.

    class DataAccess {
        private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
        private final Lock r = rwl.readLock();
        private final Lock w = rwl.writeLock();
    
        public Data readSomething(int id) {
            Cursor c = null;
            r.lock();
            try {
                c = getReadableDatabase().query(...);
                return c.getString(0);
            } finally {
                if (c != null) c.close();
                r.unlock();
            }
        }
    
        public void changeSomething(int id, int value) {
            w.lock();
            try {
                getWritableDatabase().update(...);
            } finally {
                w.unlock();
            }
        }
    
        private void beginTransactionWithSemaphores() {
            getWritableDatabase().beginTransactionWithListener(new SQLiteTransactionListener() {
                @Override
                public void onBegin() {
                    w.lock();
                }
    
                @Override
                public void onRollback() {
                    w.unlock();
                }
    
                @Override
                public void onCommit() {
                    w.unlock();
                }
            });
        }
    }
    

提交回复
热议问题