Android アプリ内で SQLite データベースに対してクエリを実行する場合のベスト プラクティスは何でしょうか?
AsyncTaskのdoInBackgroundから挿入、削除、選択クエリを実行しても安全ですか?それともUIスレッドを使うべきでしょうか?データベースクエリは「重い」可能性があり、アプリをロックする可能性があるためUIスレッドを使用すべきではないと思います。アプリケーションが応答しない(ANR)。
複数の AsyncTasks がある場合、接続を共有する必要がありますか、それともそれぞれ接続を開く必要がありますか?
これらのシナリオに対するベストプラクティスはありますか?
ベストアンサー1
挿入、更新、削除、読み取りは複数のスレッドからでも通常は問題ありませんが、ブラッドの答えは正しくありません。接続の作成方法と使用方法には注意が必要です。データベースが破損していなくても、更新呼び出しが失敗する場合があります。
基本的な答え。
SqliteOpenHelper オブジェクトは 1 つのデータベース接続を保持します。読み取りと書き込みの接続を提供しているように見えますが、実際にはそうではありません。読み取り専用を呼び出すと、書き込みデータベース接続が取得されます。
つまり、ヘルパー インスタンスが 1 つ、DB 接続が 1 つ。複数のスレッドから使用する場合でも、接続は 1 つずつです。SqliteDatabase オブジェクトは、Java ロックを使用してアクセスをシリアル化します。したがって、100 のスレッドに 1 つの DB インスタンスがある場合、実際のディスク上のデータベースへの呼び出しはシリアル化されます。
つまり、1 つのヘルパー、1 つの DB 接続が Java コードでシリアル化されます。1 つのスレッド、1000 のスレッドで 1 つのヘルパー インスタンスを共有すれば、すべての DB アクセス コードはシリアル化されます。これで、人生は順調です (ish)。
実際の異なる接続から同時にデータベースに書き込もうとすると、1 つは失敗します。最初の書き込みが完了するまで待機せず、変更が書き込まれません。さらに悪いことに、SQLiteDatabase で適切なバージョンの挿入/更新を呼び出さなければ、例外は発生しません。LogCat にメッセージが表示されるだけで、それで終わりです。
では、複数のスレッドですか? ヘルパーを 1 つ使用してください。以上です。1 つのスレッドだけが書き込みを行うことがわかっている場合は、複数の接続を使用できる可能性があり、読み取りが速くなりますが、購入者は注意してください。私はそれほどテストしていません。
より詳しい内容とサンプルアプリを記載したブログ投稿はこちらです。
- Android Sqlite ロック(リンクは2012年6月18日に更新されました)
- Android データベース ロック 衝突 例 (touchlab より)GitHubで
Gray と私は、彼の Ormlite をベースにした ORM ツールを実際に完成させています。このツールは Android データベース実装でネイティブに動作し、ブログ記事で説明した安全な作成/呼び出し構造に従います。もうすぐ公開される予定です。ぜひご覧ください。
その間、フォローアップのブログ投稿があります:
また、前述のロックの例の2point0によるフォークも確認してください。