📓

第7章:「トランザクション = 安心」のウラにある、すごく雑で不安な現実

に公開

第7章:「トランザクション = 安心」のウラにある、すごく雑で不安な現実

『データ指向アプリケーションデザイン(DDIA)』第7章を読んだメモです
トランザクション=万能、と思ってたけど全然そんなことなかった
そのギャップと現実の“設計責任”について自分なりに噛み砕きました

🔙 目次に戻る


ACIDって魔法の言葉みたいに語られがちだけど…

「トランザクションはACIDを保証してるから安心」って話、
一見頼もしそうだけど、ちゃんと読んでいくと:

  • A(Atomicity)→ ロールバックできる単位だけ
  • C(Consistency)→ DBじゃなくアプリ設計の責任
  • I(Isolation)→ 実装依存で全然意味が変わる
  • D(Durability)→ 書いた瞬間から消えない…のか?

それぞれの「実際の中身」が曖昧なことに気づく

図7: 単一ノード・ローカルトランザクションのライフサイクル


一貫性(C)は“文脈依存”。だから設計で担保しないと破綻する

「データが一貫している状態」とは何か?
これはDBが勝手に判断できるものじゃない

  • 残高がマイナスじゃない
  • 在庫数より注文数が多くない
  • 入力と合計が合ってる

といった業務ロジックのルールがないと、整合なんて語れない
ACIDの「C」は設計者の仕事そのもの


分離性(I)は「難しすぎて覚えてられない」やつランキング上位

  • Read Committed:読んだデータはもうコミット済み
  • Snapshot Isolation:トランザクション開始時点のスナップショットを見る
  • Serializable:すべての実行が順次であるかのように見える
  • Repeatable Read…ってどれだっけ?

トランザクション分離レベルは、用語が似てて混乱しがち
でも実際の処理に直結する、すごく実践的な論点


PostgreSQLはMVCCで“見える世界”を分けてくれてる

PostgreSQLはマルチバージョン同時実行制御(MVCC)を採用してて:

  • Insert/Update/Deleteのたびに新しいバージョンを追加
  • 古いバージョンは“見えなく”する
  • vacuumでようやく物理削除

「同じデータを別のトランザクションが見てる」状況でも破綻しにくい
世代管理で分離性を“擬似的に”実現してるとも言える


トランザクション分離レベルで許される or 許されない世界

たとえば:

  • ダーティーリード(未確定な値を読み取る)
  • 更新ロスト(2つの変更がぶつかって片方が消える)
  • ファントムリード(同じクエリなのに行が増える)
  • 書き込みスキュー(条件満たしてたのに、実行結果が壊れる)

このあたり、実はアプリケーションで対処しないとヤバいケースも多い
「トランザクションに任せておけば安心」では済まされない


アトミック書き込み、実は“書き込む前にチェック”でしかない

あるトランザクションが、対象レコードに対して:

  • 他のやつ書いてないよね? をチェック
  • OKだったら書く
  • ダメならリトライ or 中断

この「チェックしてから書く」流れは分散排他制御の最小単位
設計者側でバッティング条件をちゃんと設計しないと発火する


“結果として問題ない”というPostgreSQLの哲学

PostgreSQLはSerializable Isolationでもリトライによる整合性担保をする仕組みがあって:

  • 古いスナップショットをもとに処理した
  • 書き込みトランザクションにぶつかった
  • リトライして、整合性を保った形に書き直す

という「あとから帳尻合わせ」が可能
でも、これを過信すると大量リトライでパフォーマンス死ぬ


スナップショット分離が安全とは限らない理由

スナップショット分離では、トランザクション開始時点の世界しか見えない

  • 読み取った後に他の誰かが書き込んだ
  • それに気づかず別の更新をした
  • 整合性が壊れる

読んで→考えて→書くまでの一連の流れが分離されすぎると、**スキュー(歪み)**が生まれる


“トランザクション設計”とは、性能と信頼性のトレードオフ

  • 分離レベルを上げると競合が増える(整合性は強くなる)
  • 下げるとパフォーマンスは上がる(整合性は“現場任せ”)

このトレードオフをどこに落とすかが肝
しかもその判断は「今のユースケース」と「将来の使い方」を見越して決めなきゃいけない


✍️ まとめ:トランザクションは“すごく便利な不完全性”の上に成り立ってる

トランザクションって、「全部任せれば安心」な仕組みに見えて、
実際は「設計者が意思を持って制御する仕組み」だった

  • どのくらい信用するか
  • どこまで任せて、どこからはアプリで担保するか
  • その結果、どんなパフォーマンスになるか

この線引きこそが“トランザクション設計”の本質
整合性も耐障害性も、「どこまで諦めるか」で実現されてる


💡 設計Tips

  • トランザクションに任せきりにしない(業務ロジック次第で破綻する)
  • 分離レベルの選定はユースケース依存
  • MVCCの挙動を前提にすると PostgreSQL は柔軟に扱える
  • スナップショット分離でもスキューに注意
  • リトライ前提設計はパフォーマンスとの相談が必要

🔙 目次に戻る

Discussion