コンテンツプロバイダーからデータをプルする複数のアクティビティを持つアプリ(Android 2.2 Google APIレベル8)があります(データベースアクセスのみを選択してください)。また、データベース書き込みタスクを受け入れる中央ブロッキングタスクキューを備えたサービスもあります。アクティビティは、サービスリクエストを(インテントとして)起動できます。これにより、タスクがブロッキングキューに配置され、単一のスレッドによる順次取得と実行が可能になります。データベースは約4MBです。
サービスがデータベースへの書き込みを含むデータベースと対話するためのメソッドを呼び出すために使用する単一のデータベースヘルパーがあります。すべてのSQL書き込みは、データベースヘルパー内で実行されます。
- すべてのデータベース書き込みはトランザクションに囲まれています。
- すべてのデータベース読み取りでは、メソッドの最後でカーソルが閉じられます。
- どのアクティビティにもデータベースオブジェクトへのハンドルはなく、コンテンツプロバイダーまたはサービスを介してのみ通信できます。
- アクティビティなどのAlarmManagerが起動したタスクは、サービスを使用して適切なタスクをキューにポップするだけです。
- このサービスは、データベースヘルパーへのハンドルを持つ唯一のクラスです。
- すべてのデータベース書き込みは、キューに配置されたタスクを介してのみ実行されます。SQLiteデータベースへの同時書き込みを回避することが不可欠であることを十分に認識して、タスクの実行がシーケンシャルであることを徹底的に確認しました。
タスク実行の実行中に、「トランザクションの開始」のタスク実行によってトリガーされたデータベースへの書き込みを試行すると、一貫して1つまたは2つの「データベースがロックされています」エラーが発生します。
ロックの原因を突き止めようとしたところ、dbhelper.inTransaction()、dbhelper.isLockedByThisThread()、dbhelper.isLockedByOtherThread()を使用しても、予期しないデータベースロックが示されないため、役に立たなかったことがわかりました。
私が見つけたのは、ロックを早期に検出するのに役立ったのは、問題をログに記録するtry catchブロック内に、実際のSQL書き込みコードなしでbeginTransaction()とsetTransactionSuccessfulを使用してメソッドを作成することでした-常にbeginTransaction()によってトリガーされます。
このデータベースロックトラップを各ブロッキングキュータスクメソッドのいずれかの側に配置し、終了後にデータベースをロック状態のままにしていた単一の原因を見つけることを期待/期待しました。一貫した犯人を見つけることができませんでした。タスク呼び出しの開始からデータベース書き込みまでドリルダウンした後、以前に実行されたタスクによってロックされていなくても、データベースロックが一見突然発生する可能性があることがわかりました(これらのタスクはすべて、同じ単一のスレッドで順番に実行されます) )。
データベースロックの問題に関する他の多くの人々の経験を調べた後、すべてのタスクでトランザクションが完了した直後にデータベース接続を閉じようとしましたが、データベースロックがさらに発生するように思われる場合は、これは役に立ちませんでした。各タスクの実行の間にスリープを追加しようとしました。徹底的にテストされていませんが、一般的に3秒以上の遅延により、データベースロックの表示が停止するように見えることがわかりました。アラームマネージャーが起動したタスクを無効にしてみましたが、違いはありませんでした。
私が持っている印象は、アプリケーションの外部にある何らかの形式のメンテナンスタスクがデータベースに定期的にドロップインしてロックしていることです。おそらく、ログの書き込みが遅れています。明らかに、私はタスク処理の遅延を設定することに熱心ではないので、必要に応じてデータベースの書き込みを再試行するために、データベースロックの再試行タスクキューを用意することを検討しています。解決することを非常に好みますが、アイデアが不足しています。
誰かが私が逃したいくつかの原則や落とし穴を考えることができますか?
たまにデータベースロックが発生するのは、Androidや大規模なSQLiteデータベース内では実際には正常ですか?
ありがとう