質問

データベースのテーブルとカーソルにアクセスするためにAsyncTasksを使用しています。

残念ながら、データベースのロックに関して時折例外が発生しています。 ジェネラコディセタグプレ

読み取りとは異なるスレッドからデータベースに書き込むコードの一般的な例はありますか。また、スレッドの安全性を確保するにはどうすればよいですか。

私が持っていた提案の1つは、ContentProviderを使用することです。これは、複数のスレッドからのデータベースへのアクセスを処理するためです。これを見ていきますが、これはそのような問題を処理するための推奨される方法ですか?前または後ろで話していることを考えると、かなり重いようです。

役に立ちましたか?

解決

この同じ例外を解決するには、開いているすべてのデータベースが閉じていることを確認し、(さらに重要なことに)これを保証して、各データベースインスタンスのスコープをそれを必要とするメソッドに対してのみローカルにします。ContentProviderは、複数のスレッドからデータベースにアクセスするときに使用するのに適した安全なクラスですが、適切なデータベースプラクティスを使用していることも確認してください。

  • dbインスタンスをローカルに保持します(SQLiteDatabaseクラスのメンバーは使用しないでください)
  • データベースを開いたときと同じ方法でデータベースのclose()を呼び出します
  • データベースから取得したカーソルでclose()を呼び出します
  • SQLiteDatabseからの苦情についてはLogCatを聞いてください

他のヒント

最後にContentProviderを使用しました。これで問題が解決したようです。

コードの前に、いくつかのアプローチを再開しましょう。

  • セマフォ :提示された最善のソリューション。それは問題の核心にあります:リソース共有!データベースアクセスのロックを処理し、競合を回避します(database is locked)。

  • Java同期 :一種のセマフォ実装ですが、それほど洗練されていません。 synchronizedを使用すると、トランザクションに関連するいくつかのケースを簡単に解決できません。

  • ContentProvider ContentProviderを実装して、一部のケースでのみ問題を解決します(またはカーペットの下で問題を一掃します)。あなたはまだ同じ問題に直面するでしょう。違いは、ContentProviderパターンは、Sqliteデータベースにアクセスするときにいくつかの一般的な間違いをしないようにガイドすることです。 ContentProviderドキュメントは次のように述べています:「あなたはしません完全に独自のアプリケーション内で使用する場合は、SQLiteデータベースを使用するプロバイダーが必要です。」

  • ほぼ必須 :dbインスタンスをローカルに保ち、dbでclose()を呼び出しますfinallyステートメントを使用して開くのと同じ方法で、close()ステートメントを使用するカーソル上のfinallyなどは、Sqliteの使用に関する問題を回避するためにほぼ必須です。

    Mossによって提示されたセマフォソリューションの例を示しましょう。これはCL。およびトランザクションをカバーするために改良されました。 ジェネラコディセタグプレ

SQLiteデータベースはファイルベースであり、マルチプロセスの方法でアクセスできるようにすることを目的としていないことを考慮に入れてください。SQLiteをマルチプロセッシングと混合するための最良の手順は、データベースに関連する各アクセスでセマフォ(aquire()、release())を使用することです。

グローバルセマフォを取得/解放するDbラッパーを作成すると、DBアクセスはスレッドセーフになります。実際、これは、DBへのアクセスをキューに入れているため、ブートレネックが発生する可能性があることを意味します。したがって、さらに、データベースを変更する操作である場合にのみ、セマフォを使用してアクセスをラップできます。したがって、データベースを変更している間は、誰もデータベースにアクセスして、書き込みプロセスが完了するまで待つことができません。

データベースで読み取りと書き込みの操作を同時に実行するために複数のスレッドとDb接続を共有できませんでした。同期の概念を使用してDBの単一のオブジェクトを作成する必要があり、一度に1つのタスクを実行します。シングルトンパターンを使用してDBオブジェクトを作成すると、複数のスレッド内で共有されます。一度に1つのタスクを実行します。次に、DBで他のタスクまたは操作を開始します。 コンテンツプロバイダーは、DBロックの問題の解決策ではありません。 ジェネラコディセタグプレ

そして、SQLiteOpenHelperクラスを拡張するYourSQLiteDataABseヘルパークラスにこのメソッドを記述します ジェネラコディセタグプレ

dbヘルパークラスのコンストラクターではなく、関数からgetWritableDatabase()を呼び出す必要があります。dbヘルパークラスオブジェクトがSQLiteDatabase.openOrCreateDatabase(DB_PATH, null);などで作成され、関数からgetWritableDatabase()が呼び出されると、DBへの同期呼び出しが試行され、DBロック例外が発生します。

プログラム内で複数のスレッドが実行され、そのうちの複数が更新モードでデータベースにアクセスしている可能性がある単一のユーザーアクションについて話しているのですか?

それは悪いデザインです、期間。OS(/ VM)によってスレッドがスケジュールされる順序を知る方法はありません。したがって、データベースアクセスが発生する順序を知る方法はありません。これは、ほとんどの場合、データベースアクセスが常に期待どおりの順序で行われることを知る方法はありません。

ユーザーアクションによって生成された、またはユーザーアクションから発生したすべてのデータベースアクセスは、すべて1つのスレッドで実行する必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top