5

私は SQLiteOpenHelper を使用して、Android 上の SQlite データベースから読み書きしています。ユーザーがUIをクリックすると、AsyncTaskを使用してSQLiteデータベースから読み取りますが、正確な瞬間に、他のAsyncTaskを使用してバックグラウンドでデータベースを更新して書き込みます。

x回ごとにデータベースロック例外が発生します。どうすればこれを修正できますか? 複数のスレッドから同時にSQliteにアクセスすることはできますか?

私はそのように使用しています: SQLiteOpenHelper から拡張されたデータベース クラスがあります。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 answer を使用して、アプリケーションにデータベース クラスのシングルトンを設定する必要がありますか?

これは私が得るエラーです:

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

4 に答える 4

7

これは、ロックの問題を回避するために私が行っていることです。アプリケーションで db ヘルパーの単一のインスタンスを処理し、常にそれを参照して DB のハンドルを取得します。

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

これを行うと、db クエリを実行したいときはいつでも MyApp.getDB() のような db ハンドルを取得でき、ロックの問題が発生することはありません。ただし、DBを閉じないでください。このパターンは、アプリ内で常に 1 つの接続を維持します。SQLite は Android で同期することを意図しているため、単一のトランザクションで 1000 回の挿入など、長時間実行される DB プロセスがある場合は、次のようにコーディングする必要があります。

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

これにより、他のクエリが自分自身に割り込むことができるため、バックグラウンド更新中にアプリが停止することはありません。

于 2012-10-19T15:28:10.500 に答える
1

試すべきことがいくつかあります。SQLiteOpenHelperまず、すべてのタスクに同じインスタンスを渡してみてください。2つ目は、ヘルパー内のSQLiteDatabaseでbeginTransactionとendTransactionを使用することです。3つ目はsynchronized、タスクで使用されているすべてのヘルパー方法を追加することです。

于 2012-10-19T12:49:39.663 に答える
0

データベース接続を誤って使用していると思います。閉じていないカーソルまたはその他の問題が原因である可能性があります。Sqliteデータベースの実装はスレッドセーフであり、異なるスレッドから同時にアクセスできます。問題の詳細(例外スタックトレース、例外の原因となるコードサンプルなど)をお知らせください。サポートさせていただきます。

于 2012-10-19T12:50:39.883 に答える