1

I want to know what happens behind the scenes which causes this exception "SQLiteDatabaseLockedException" to be thrown with message "database is locked".

I am not asking for resolving this exception (because I already did it.) I want to know how the things are working in background. I had gone through the source code of classes SQLiteOpenHelper and SQLiteDatabase.Both these classes are Thread-safe as the methods are synchronized (or using synchronized block).

I did not find any line which says "throw new SQLiteDatabaseLockedException("database is locked). I also read the classes which are refered in SQLiteDatabase like SQLiteConnection, SQLiteConnectionPool, but did'nt find anything useful. I read somewhere on the internet that SQLite maintains its internal locking. Is it means the native libraries of SQLite?

Please someone explains in depth what is happening behind the scenes. Thanks.

Naveen
  • 21
  • 8
  • Generally these kind of exception received when you try to open data base while is it already open.Best practice says always close your db once it it no longer in use. – Ravi Bhandari Apr 30 '15 at 05:25
  • http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/database/sqlite/SQLiteDatabaseLockedException.java – Amsheer Apr 30 '15 at 05:27
  • 1
    The line number and class name are displayed in the logcat.. –  Apr 30 '15 at 05:32
  • Thanks for reply but what I know this exception occurs when one thread is accessing the database and another thread want to access the database with a different connection. I want to know which particular class and method throws this exception as I didn't find it in the android source code. – Naveen Apr 30 '15 at 05:32

1 Answers1

0

I have faced your problem a few months ago and struggle against it a day or two...

Your problem is in the connections. You must not use different connections because each active connection locks the database when it uses it. If you want to execute parallel operations over the database, you can still use threads but take in mind that you must do the synchronization in your java code. You have two options for synchronization:

  • java locking mechanisms: synchronized and locks
  • SQL transactions

I advise you to use both. Use transactions everywhere you are performing DB operation (no matter if you are doing it in parallel or not). This way you will be safe from experiencing future problems with reading wrong/old/partial data. Use the java concurrent API when you are dealing with concurrent access to java objects that are related to the database (e.x: a counter that tracks the number of parallel java consumers of the database, the db helper instance, etc).

I have used the following code to manage the access to the database connection. I hope this snippet will help you solve your problems. Take in mind that this code snippet is taken from an existing project so it contains references to class name and methods that are not shown here but I hope the basic idea is clear.

/**
 * Defines the supported database types of access
 */
public enum AccessType {
    READABLE, WRITABLE;
}

protected static volatile SQLiteDatabase sDatabase;
private static volatile int sCounter;
private static final Object LOCK = new Object();

/**
 * Opens the database for access.
 * 
 * @param accessType
 *            The type of access to be used.
 * @throws SQLException
 *             If something goes wrong.
 */
public final void open(final AccessType accessType) throws SQLException {
    synchronized (LOCK) {
        sCounter++;

        if (sDatabase != null && sDatabase.isOpen()) {
            return;
        }

        switch (accessType) {
        case READABLE: {
            sDatabase = mDBHelper.getReadableDatabase();
            break;
        }
        case WRITABLE: {
            sDatabase = mDBHelper.getWritableDatabase();
            break;
        }
        default:
            throw new IllegalArgumentException("This AccessType is not supported!");
        }
    }
}

/**
 * Closes the database connection.
 */
public final void close() {
    synchronized (LOCK) {
        sCounter--;

        if (sCounter == 0 && sDatabase != null && sDatabase.isOpen()) {
            sDatabase.close();
        }
    }
}

@Override
public final void create(final T entry) {
    sDatabase.beginTransaction();
    try {
        doCreate(entry);
        sDatabase.setTransactionSuccessful();
    } finally {
        sDatabase.endTransaction();
    }
}
jmart
  • 2,769
  • 21
  • 36
Kiril Aleksandrov
  • 2,601
  • 20
  • 27
  • Thanks for Reply but am not asking for solution. Because I already solve it. Am just want know the inner details regarding how locking it working in SQLite in Android when accessing from Multiple threads. – Naveen Apr 30 '15 at 09:24
  • volatile does not belong in there – sstn May 17 '16 at 13:07