SQLite をデータベースとして使用してアプリケーションを開発していますが、それを複数のスレッドで使用する方法を理解するのに少し苦労しています(残念ながら、他のStack Overflowの質問はまったく役に立ちませんでした)。
私のユースケース:データベースには1つのテーブルがあり、それを「A」と呼びましょう。これには、列の1つに基づいて異なる行グループがあります。テーブルAからコンテンツを読み取るアプリケーションの「メインスレッド」があります。さらに、ときどき、特定の行グループを更新することにしました。これを行うには、新しいスレッドを生成し、グループのすべての行を削除し、それらを再挿入します(これがアプリのコンテキストで行う唯一の方法です)。これは同時に異なるグループで発生する可能性があるため、2つ以上のスレッドがデータベースを更新しようとしている可能性があります。
私は各スレッドから異なるトランザクションを使用しています、つまりすべてのスレッドの更新サイクルの開始時に開始します。実際、各スレッドが実際に行うのは、「BEGIN」を呼び出し、データベースから「更新」する必要があるすべての行を削除し、新しい値で再度挿入します(これは、myのコンテキストで行う必要がある方法です)応用)。
今、私はこれを実装する方法を理解しようとしています。読んでみました(SQLiteサイト、Stack Overflowのその他の回答)が、すべての回答が見つかりませんでした。ここに私が疑問に思っていることがいくつかあります:
誰かが質問に答えたり、良いリソースの方向に私を向けることができるなら、私はとても感謝しています。
UPDATE 1:これまで読んだことから、データベースファイルに書き込むスレッドを2つ持つことはできないようですとにかく。
参照: http://www.sqlite.org/lockingv3.html セクション3.0:予約済みロックは、プロセスが将来のある時点でデータベースファイルへの書き込みを計画しているが、現在はファイルからの読み取りのみを行っていることを意味します。一度にアクティブにできるのは、1つのRESERVEDロックだけです。ただし、複数のSHAREDロックが1つのRESERVEDロックと共存できます。
これは、毎回行のグループを更新するために単一のスレッドからのみスポーンできることを意味しますか?つまり、行の一部を更新する必要があると判断したポーラースレッドがあり、それを実行するために新しいスレッドを作成しますが、一度に複数のスレッドを作成することはありませんか?私が作成した他のスレッドのように見えるので、とにかく最初のスレッドが終了するまでSQLITE_BUSYを取得します。
物事を正しく理解しましたか?
ところで、これまでの回答に感謝し、彼らは多くを助けてきました。
このリンク をご覧ください。最も簡単な方法は、自分でロックを行い、スレッド間で接続を共有しないようにすることです。別の優れたリソースを見つけることができます here
-DTHREADSAFE = 1を指定してSQLiteをコンパイルしていることを確認してください。
各スレッドがデータベースファイルを開き、独自のsqlite構造を保持していることを確認してください。
1つ以上のスレッドが同時にdbファイルにアクセスするときに衝突する可能性を処理するようにしてください。SQLITE_BUSYを適切に処理してください。
データベースファイルを変更するコマンド(INSERT、UPDATE、DELETEなど)をトランザクション内に含めるようにしてください。
マルチスレッドで使用するためにSQLliteを開始するときのいくつかの手順:
私はこれが古いスレッドであり、応答が良いことを理解していますが、最近これを調べていて、いくつかの異なる実装の興味深い分析に出会いました。主に、接続の共有、メッセージの受け渡し、スレッドローカル接続、接続プーリングの長所と短所について説明します。こちらをご覧ください: http://dev.yorhel.nl/doc/sqlaccess
SQLiteの最新バージョンでは、デフォルトでスレッドセーフが有効になっています。 _SQLITE_THREADSAFE
_ コンパイルフラグは、マルチスレッド環境で安全に動作できるようにコードをSQLiteに含めるかどうかを制御します。 デフォルトの値は_SQLITE_THREADSAFE=1
_です。 Serialized mode を意味します。このモードでは:
このモード(SQLiteがSQLITE_THREADSAFE = 1でコンパイルされている場合のデフォルト)では、SQLiteライブラリ自体がデータベース接続と準備済みステートメントへのアクセスをシリアル化し、アプリケーションが同じデータベース接続または異なるスレッドで同じ準備済みステートメントを自由に使用できるようにします同時に。
sqlite3_threadsafe()
関数を使用して、Sqliteライブラリ_SQLITE_THREADSAFE
_コンパイルフラグを確認します。
デフォルトのライブラリスレッドセーフ動作は、sqlite3_config()
を介して変更できます。個々のデータベース接続のスレッドモードを調整するには、sqlite3_open_v2()
で_SQLITE_OPEN_NOMUTEX
_および_SQLITE_OPEN_FULLMUTEX
_フラグを使用します。
概要
SQLiteのトランザクションはシリアライズ可能です。
1つのデータベース接続で行われた変更は、コミット前の他のすべてのデータベース接続からは見えません。
クエリは、それらの変更がコミットされているかどうかにかかわらず、クエリの開始前に同じデータベース接続で完了したすべての変更を確認します。
クエリの実行開始後、クエリが完了する前に同じデータベース接続で変更が発生した場合、クエリがそれらの変更を表示するかどうかは未定義です。
クエリの実行開始後、クエリが完了する前に同じデータベース接続で変更が発生した場合、クエリは変更された行を複数回返すか、以前に削除された行を返すことがあります。
前の4つの項目の目的のために、同じ共有キャッシュを使用し、PRAGMA read_uncommitted
を有効にする2つのデータベース接続は、個別のデータベース接続ではなく、同じデータベース接続と見なされます。
マルチスレッドアクセスに関する上記の情報に加えて、この最初の質問と先行書き込みログの導入以来多くのことが変更されているため、 分離に関するこのページ を調べる価値があります。 ([〜#〜] wal [〜#〜])。
データベースへの複数の接続を開くハイブリッドアプローチは、適切な同時実行性の保証を提供し、マルチスレッド書き込みトランザクションを許可するという利点と新しい接続を開く費用をトレードオフします。