【要約】Prisma のトランザクション内で `Promise.all` を使っても速くならない [Qiita_Trend] | Summary by TechDistill
> Source: Qiita_Trend
Execute Primary Source
// Problem
開発者が、複数のDB更新処理を効率化しようとしてPromise.allを導入する際、以下の技術的課題に直面する。
- ・トランザクション内でのパフォーマンス不足:Prismaのトランザクション内では、同一のDBコネクションを使用するため、Promise.allを用いてもクエリは実質的に直列実行され、高速化の恩恵を受けられない。
- ・データ整合性の喪失:トランザクション外でPromise.allを使用した場合、複数の更新のうち一部が失敗しても他の更新が確定してしまい、データが中途半端な状態になるリスクがある。
// Approach
開発者は、関数の設計においてトランザクションの管理範囲を明確にするアプローチを採用すべきである。具体的には、以下の2つの設計方針がある。
- ・方針1:TransactionClient専用関数にする。引数として
tx: Prisma.TransactionClientを強制的に受け取る設計とし、呼び出し側がトランザクションの境界を制御する。 - ・方針2:関数内でトランザクションを開始する。関数内部で
db.$transactionを呼び出し、関数単体で「全成功か全失敗か」の原子性を保証する設計とする。
// Result
適切な設計指針を適用することで、開発者は以下の成果を得られる。
- ・データ整合性の確保:不適切なPromise.allの使用を避け、明示的なトランザクション管理を行うことで、中途半端なデータ更新を防止できる。
- ・コードの意図の明確化:
for...ofによる順次実行や、専用のクライアント引数を用いることで、処理が直列であることやトランザクションへの依存関係を後続のエンジニアに正しく伝えられる。
Senior Engineer Insight
> 「JSの非同期処理」と「DBの物理的制約」の乖離を突いた、極めて実戦的な指摘である。大規模システムでは、並列化による微小な速度向上よりも、データの原子性を守る設計が遥かに重要だ。特に、関数のデフォルト引数で
client = dbとする設計は、呼び出し方次第で挙動が激変するため、極めて危険である。設計段階で「この関数は単体で完結するか、外部のトランザクションに依存するか」を厳格に定義すべきである。