Android SQlite多线程访问

时间:2012-10-19 12:21:53

标签: android database multithreading android-sqlite

我正在使用SQLiteOpenHelper在Android上编写和读取SQlite数据库。当用户点击UI时,我使用AsyncTask从SQLite数据库中读取,但在确切的samo时刻,我正在使用其他AsyncTask更新并在后台写入数据库。

每隔x次我就会遇到数据库锁定异常。我怎样才能解决这个问题?可以同时从多个线程以某种方式访问​​SQl​​ite吗?

我正在使用它:我有一个从SQLiteOpenHelper扩展的Database类。我实现了onCreate和onUpgrade方法,每当我从数据库读取或写入数据库时​​,我都使用SQLiteDatabase:

SQLiteDatabase database = null;
try {

    database = new Database(context).getWritableDatabase();

    ....
    writing and reading from database...
    ....

} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (database != null) {
        database.close();
    }
}

最后,如果我使用它们,我也会关闭SQLiteStatements和Cursors。我应该使用@Justin答案并在Application中使用单例数据库类吗?

这是我得到的错误:

E/SqliteDatabaseCpp(17377): sqlite3_open_v2("/data/data/com.skulptur/databases/LGM.s3db", &handle, 6, NULL) failed
E/SQLiteDatabase(17377): Failed to open the database. closing it.
E/SQLiteDatabase(17377):     android.database.sqlite.SQLiteDatabaseLockedException: database is locked
E/SQLiteDatabase(17377):    at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
E/SQLiteDatabase(17377):    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:983)
E/SQLiteDatabase(17377):    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:956)
E/SQLiteDatabase(17377):    at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1021)
E/SQLiteDatabase(17377):    at   android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:750)
E/SQLiteDatabase(17377):    at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221)
E/SQLiteDatabase(17377):    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:149)
E/SQLiteDatabase(17377):    at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:223)

4 个答案:

答案 0 :(得分:7)

这是我为避免锁定问题而做的事情。我让我的应用程序处理我的数据库帮助程序的单个实例,并始终引用它来获取我的数据库的句柄。

public class MyApp extends Application {
    // My instance of SQLiteOpenHelper
    public static DbHelper openHelper;

    @Override
    public void onCreate() {
        super.onCreate();
        if (openHelper == null) {
            openHelper = new DbHelper(this);
        }
    }

    public synchronized static SQLiteDatabase getDB() {
        return openHelper.getWritableDatabase();
    }
}

一旦你这样做,任何时候你想要进行数据库查询,获取像MyApp.getDB()这样的数据库句柄,你将永远不会遇到锁定问题。请务必不要关闭数据库。此模式在您的应用中始终保持单个连接。 SQLite意味着在Android上是同步的,所以如果你有长时间运行的数据库进程,比如单个事务中的1000个插入,你需要像这样编写代码:

db.beginTransaction();
try {
    for (DBRow row : insertList) {
        // your insert code
        insertRow(row);
        db.yieldIfContendedSafely();
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}

这将允许其他查询插入自己,这样您就不会在后台更新期间看到您的应用停止运行。

答案 1 :(得分:3)

使用ContentProvider在数据库顶部实施Loaders,它将处理线程。 您可以参考本教程:http://www.vogella.com/articles/AndroidSQLite/article.html

答案 2 :(得分:1)

有几件事要尝试。 首先尝试将SQLiteOpenHelper的相同实例传递给您的每个任务。 其次是在Helper内部的SQLiteDatabase上使用beginTransaction和endTransaction。 第三是将synchronized添加到任务中使用的每个辅助方法中。

答案 3 :(得分:0)

我认为您错误地使用了数据库连接。它可能是由未关闭的游标或其他游戏引起的。 Sqlite数据库实现是线程安全的,可以从不同的线程同时访问。 请提供有关您的问题的更多详细信息(异常堆栈跟踪,导致异常的代码示例等),以便我们为您提供帮助。