Sqliteマルチスレッドに関する研究
6067 ワード
研究プロセス
一、キャッシュ需要
最近appを最適化し,すべてのネットワーク要求で返されるjsonデータをキャッシュしたい.
二、キャッシュシーンの多様化とキャッシュ方案の統一
appで使用されるネットワークリクエストにはHttpClientとOkHttpやVolleyなどのサードパーティネットワークフレームワークがあり、サードパーティネットワークフレームワークによってキャッシュの使用方法が異なり、HttpClientは独自にキャッシュを実現する必要があるため、jsonデータをsqliteデータベースに緩和するソリューションを統一的に採用している.
三、ネットワーク要求のマルチスレッドシーンによるsqliteマルチスレッド問題
ネットワークリクエストにマルチスレッドが存在する場合,さらにsqliteもマルチスレッドの場合を処理しなければならない.
四、sqliteマルチスレッド問題の解決方案
sqlite内部では大粒度のファイルロックが使用されているため、書き込みと同時に問題が発生します.実際にsqliteはマルチリードライトをサポートしています.
1、単例(Singleton)或いはsychronized——読み取り同期、読み書き同期、書き込み同期
この方法でビッグデータを処理すると、ブロックであるため、パフォーマンスに問題があります.また、データベースの解放タイミングに注意する必要があります.そうしないと、次のバグが表示されます.
java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:599)
at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
このバグを修正する正しい方法は次のとおりです.
public class XXXDao {
private AtomicInteger mOpenDBCounter = new AtomicInteger();
private static XXXDao dao = null;
private final XXXHelper helper;
private SQLiteDatabase db;
public XXXDao (Context context){
helper = new XXXHelper (context);
}
public static synchronized XXXDao getInstance(Context context){
if(dao == null){
dao = new XXXDao (context);
}
return dao;
}
public synchronized SQLiteDatabase openWDatabase() {
if(mOpenDBCounter.incrementAndGet() == 1) {
// Opening new database
if(null!=helper){
db = helper.getWritableDatabase();
}
}
return db;
}
public synchronized void closeDatabase() {
if(mOpenDBCounter.decrementAndGet() == 0) {
// Closing database
db.close();
}
}
}
2、非単例(多読、一書)——読読同時、読写同期、書写同期
データベース操作ではaddのみ、delete、updateではlock()が呼び出され、query()では呼び出されませんが、データのロード時にSQLiteQueryのfillWindowメソッドが呼び出され、このメソッドではSQLiteDatabaseが呼び出されます.lock()ですので、マルチスレッド読み取りデータベースを実装するには、各スレッドがそれぞれのSQLiteOpenHelperオブジェクトを使用して読み取り操作を行うしかありません.これにより、同期ロックを回避できます.
3、非単例(多読、一書)——読読同時、読写同時、書写同期
マルチスレッド読み書きを実現する鍵はenableWriteAheadLogging属性であり、この方法はAPI Level 11が追加したものであり、つまり3.0以上のバージョンでは真のマルチスレッド読み書きを実現することはほとんど不可能である.簡単に言えばenableWriteAheadLogging()とdisableWriteAheadLogging()を呼び出すことで、データがマルチスレッド読み書きを実行するかどうかを制御できます.許可されると、1つの書き込みスレッドが複数の読み取りスレッドと同時に1つのSQLiteDatabaseで機能することができます.実現原理は、書き込み操作が実際には単独のlogファイルであり、読み取り操作は元のデータファイルであり、書き込み操作が開始される前の内容であり、互いに影響しない.書き込み操作が終了すると、読み取り操作によって新しいデータベースの状態が認識されます.しかし、同時読み書きの需要がなければ、WALを開かないほうがいい.メモリの消費量が増加し、読み取りと書き込みの速度に影響を与える可能性があります.
4、非単例(多読、多写)——読解同時、読写同時、書写同時
SQLiteでは、書き込みの同時実行はサポートされていません.実際に必要な場合は、複数のデータベース・ファイルを使用して、異なるテーブルを異なるデータベースに配置します.