理系学生日記

おまえはいつまで学生気分なのか

PoEAA: Unit of Work

今日からは Chapter 11. Object-Reational Behavioral Patterns という新章に突入します。 その一つめのパターンは Unit of Work でした。

Unit of Work の概要

Unit of Work は、データベースに対して実施しなければならない操作 (一般には CRUD ということになります) を維持していくパターンです。

DB に対する変更の必要が生じる都度 INSERT/DELETE/UPDATE なんかを実行していくとパフォーマンス影響が生じますし、トランザクションがクライアントサイドからの複数のリクエストに跨るのを制御するのは難しいため、これらを解決するパターンとして登場しました。 Unit Of Work では、業務トランザクションにおいて実行すべき DB 操作を維持し、業務トランザクション完了時点でそれを DB に commit します。

Unit of Work の使われ方

当然ながら、どういうオブジェクト(が表現する DB データ)にどういう更新が入るかを Unit of Work に知らせる必要がありまして、どういう風に知らせるかというパターンは 2 種類存在します。

  1. 呼出側が Unit Of Work に登録する -- これは単純に、ドメインロジックの開発者が unitOfWork.registerDirty(object) といった形でコーディングするイメージですね。単純ですが分かりやすく、そして、開発者が登録を忘れると当然 Unit of Work は何もできません。
  2. オブジェクトが自動的に Unit of Work に登録する -- これは、データを表現するドメインオブジェクト自身が、自動的に Unit Of Work に登録するイメージです。例えば、ドメインオブジェクトが DB のデータから生成された場合は、その生成メソッドの中で unitOfWork.registerNew(this) みたいなかんじなるでしょうし、Setter が呼び出された場合は、unitOfWork.registerDirty(object) というようなメソッド呼び出しが必要になります。 -- 1. のパターンと比較すると、Unit Of Work に対する登録の責務が、ドメインオブジェクトの開発者に移ったイメージでしょうか。

ただ、こんなことを人類が完全に行うことができないのは歴史が証明しているので、ここはアスペクト指向の出番かもしれません。

また、DB に対するコミットが Unit of Work という仕組みに一元化されることから、

  • 参照整合性を確保しやすくなる (update するときのテーブル順が容易に制御できる)
  • デッドロックの可能性を極小化できる
  • batch update を実行しやすく、パフォーマンスメリットがある

といったメリットも生じます。

感想

とても便利な仕組みだと思います。 そして便利な仕組みであるが故か、正しく実装するのはとてもダルいだろうなぁという印象を持っていましたが、PoEAA 上のサンプルが非常に簡潔だったことにわりと衝撃を受けました。 ※もちろん、ここでは参照整合性を確保やデッドロック云々は実装上入っていないのですが。

このパターンの実装、とても綺麗だと思うのですが、この実装を使う側への説明とその徹底(登録や更新をするときは必ず Unit of Work を使用する)が難しいのと、それを自動化しようとすると可読性が下がるのとで、なかなか適用はハードルが高そうです。。。