在Android中导致抛出SQLiteDatabaseLockedException异常

时间:2015-04-30 05:23:07

标签: android database multithreading sqlite locked

我想知道幕后会发生什么导致此异常“SQLiteDatabaseLockedException”会抛出消息“数据库被锁定”。

我不是要求解决这个异常(因为我已经做过了。) 我想知道事情是如何在后台运作的。我已经浏览了SQLiteOpenHelper和SQLiteDatabase类的源代码。这些类在方法同步(或使用synchronized块)时是线程安全的。

我没有找到任何说“抛出新SQLiteDatabaseLockedException(”数据库被锁定)的行。我还阅读了SQLiteDatabase中提到的类,如SQLiteConnection,SQLiteConnectionPool,但没有找到任何有用的东西。我在互联网上的某处读到SQLite保持其内部锁定。它是否意味着SQLite的本地库?

请有人深入解释幕后发生的事情。 感谢。

1 个答案:

答案 0 :(得分:0)

几个月前我遇到了你的问题并且在一两天内与它斗争......

您的问题在于连接。您不能使用不同的连接,因为每个活动连接在使用它时都会锁定数据库。如果要对数据库执行并行操作,仍可以使用线程,但请记住必须在java代码中执行同步。您必须选择同步:

  • java锁定机制:synchronized和锁
  • SQL事务

我建议你两者兼用。在执行数据库操作的任何地方使用事务(无论您是否并行执行)。通过这种方式,您可以安全地避免阅读错误/旧/部分数据的未来问题。在处理与数据库相关的java对象的并发访问时使用java并发API(e.x:跟踪数据库的并行java使用者数量的计数器,db帮助程序实例等)。

我使用以下代码来管理对数据库连接的访问​​。我希望这段代码可以帮助您解决问题。请记住,此代码段取自现有项目,因此它包含对此处未显示的类名称和方法的引用,但我希望基本思路清晰。

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