TOP(About this memo)) > 一覧(Firestore) > トランザクション
トランザクション
- https://firebase.google.com/docs/firestore/manage-data/transactions?hl=ja
- トランザクション、バッチ書き込み
- 1 回のトランザクションまたはバッチ書き込みでは、最大 500 のドキュメントに書き込みを行うことができる。
- 同時編集の場合は再試行される。
- たとえば、トランザクションがドキュメントを読み取り、別のクライアントがそれらのドキュメントを変更すると、Cloud Firestore はトランザクションを再試行する。
- この機能により、常に整合性のある最新データに対してトランザクションが実行される
- 制約
- 読み取りオペレーションは書き込みオペレーションの前に実行する必要がある。
- トランザクションが読み取るドキュメントに対して同時編集の影響が及ぶ場合は、トランザクションを呼び出す関数(トランザクション関数)が複数回実行されることがある。
- トランザクション関数はアプリケーションの状態を直接変更してはいけない。
- クライアントがオフラインの場合、トランザクションは失敗
- トランザクション関数は複数回実行される可能性があり、UIスレッドに対して実行される保証がなく、状態を変更してしまうと同時実行の問題が生じる。
- トランザクションの失敗する原因
- トランザクションで書き込みオペレーションの後に読み取りオペレーションが実行される
- トランザクションが、トランザクション外部で変更されたドキュメントを読み取る(この場合、トランザクションは自動的に再実行され、一定の回数で再試行される)。
- トランザクションが最大リクエスト サイズである 10 MiB を超えている
- トランザクションのサイズは、トランザクションによって変更されたドキュメントとインデックス エントリのサイズによって異なる。削除オペレーションの場合、トランザクションのサイズには、対象ドキュメントのサイズと、オペレーションに伴い削除されるインデックス エントリのサイズが含まれる。
- トランザクションが失敗するとエラーが返され、データベースには何も書き込まれない。
- トランザクションのロールバックは不要。こちらは Cloud Firestore により自動的に実行される。
- トランザクション内でできる走査
- 任意の数の get() オペレーション
- 任意の数の書き込みオペレーション(set()、update()、delete() など)
- バッチ書き込み
- トランザクションとは異なり、バッチ書き込みでは、読み取りドキュメントが変更されていないことを確認する必要がないため、失敗するケースが少なくなる。
- 再試行の対象ではなく、過剰な再試行による失敗の影響を受けない。(…過剰な再試行による失敗、とは具体的には?)
- ユーザーのデバイスがオフラインの場合でも実行できる。
- データの一括入力として、サーバークライアントのほうが並列で優れた性能を発揮する。
トランザクションの競合
- https://firebase.google.com/docs/firestore/transaction-data-contention?hl=ja
- 競合は、データベースにおける次のような要件によって発生
- トランザクションには正確で一貫性のあるデータが必要
- リソースを効率的に使用するため、データベースはオペレーションを同時実行
- Cloud Firestore は、いずれかのオペレーションを遅延または失敗させることで、データ競合を解決する。
- データ競合が原因で失敗したトランザクションは、Cloud Firestore クライアント ライブラリによって自動的に再試行。
- 一定回数の再試行が行われると、トランザクション オペレーションは失敗し、エラー メッセージが返される。
- モバイル SDK とウェブ SDK
- オプティミスティック同時実行制御
- レイテンシが高く信頼性が低いネットワーク接続環境でも動作できるようにするため。高レイテンシ環境でドキュメントをロックすると、データ競合による失敗があまりにも多く発生することになるため。
- データベースをロックしない。
- ランザクション内で読み取ったすべてのドキュメントをトランザクションが追跡。トランザクションの実行時にこれらのドキュメントが変更されていない場合にのみ、トランザクションによって書き込みオペレーションが行われる。
- ドキュメントが変更されていた場合は、トランザクション ハンドラはトランザクションを再試行する。
- 何度か再試行してもトランザクションがクリーンな結果を得られなかった場合、データ競合によりトランザクションは失敗する。
- サーバー クライアント ライブラリ
- ペシミスティック同時実行制御
- 低レイテンシであることと、データベースとの接続の信頼性が高いことを前提としている。
- データベースをロックする。
- ロックは時系列順に取得される。
- commit 時、またはなんらかの理由でタイムアウトまたは失敗した場合にもロックが解除される。
- 他の書き込みオペレーションは、そのトランザクションによってロックが解除されるのを待つ必要がある。
- 直列化可能な分離(Serializable isolation)
- 直列化可能な分離とは、次のことを意味
- データベースがトランザクションを順に実行していると仮定できる
- トランザクションは、同時実行されているオペレーションの commit されていない変更の影響を受けない
- IMO
- 実際に並列実行(同時実行)しているかどうかは別として、それぞれのトランザクションが順番にcommitされ、かつ処理途中の他のトランザクションからの影響を受けないということが「直列化可能な分離」である、という理解であっている?
- Cloud Firestore は、トランザクションの直列化可能な分離を保証。
- Cloud Firestore は各トランザクションに単一の時点を表す commit 時間を割り当て、以下を保証。
- Cloud Firestore は、commit 時間の順番でトランザクションを commit
- Cloud Firestore は、commit 時間が後の同時実行オペレーションからトランザクションを分離
- ただし、トランザクションを実際に実行するには一定の時間の幅が必要のため、複数のオペレーションの実行が重なって実行された際は、オプティミスティック同時実行制御・ペシミスティック同時実行制御によってこれを競合を解決する。
- トランザクション内の書き込みの分離
- あるトランザクション内で書き込みされた内容は、同一のトランザクション内で読み込みされることは無い。したがって、そのトランザクションで読み取りされるドキュメントは、すべてそのトランザクションの前のcommit時間のバージョンのものとなる。
- この話題はトランザクションにおいてはドキュメントの書き込み前に読み取りを行う必要がある、という制約と関連する。
クライアントサイドからのトランザクション
- https://firebase.google.com/docs/firestore/solutions/aggregation?hl=ja
- トランザクションで複数の読み取り、書き込み、更新オペレーションが実行される場合、Cloud Firestore バックエンドに対して複数のリクエストが必要になる可能性がある。モバイル デバイスの場合、処理に時間がかかることがある。
- ユーザーのデバイスがオフラインの場合、クライアントサイドのトランザクションは失敗する。アプリでこのケースに対応し、適切なタイミングで再試行を行う必要がある。
- トランザクションで複数の読み取り、書き込み、更新オペレーションが実行される場合、Cloud Firestore バックエンドに対して複数のリクエストが必要になる可能性がある。モバイル デバイスの場合、処理に時間がかかる可能性がある。