PoEAA ch11 Unit of Work
Unit of Work
Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.
- DBへの変更をともなうオブジェクトの変更を追跡する
- 生成
- 削除
- 更新
- オブジェクトの変更のたびにDBアクセスするのは良くない
- ビジネストランザクションのcommit時にDBへの変更をまとめて反映する
How It Works
- オブジェクトの生成、更新、削除時にはUnit of Workに登録する
- inconsistent readを防ぐためにも使用する
- ビジネストランザクションの中で、以前読み出した内容から更新されていないか
- Unit of Workによるビジネストランザクションのcommit
- システムトランザクションを開始する
- 並列制御
- Pessimistic Offline Lock
- Optimistic Offline Lock
- DBに変更を書き込む
- オブジェクトの変更の追跡様式にはいくつか種類がある
- caller registration
- object registration
- unit of work controller
- caller registration
- caller = オブジェクトを生成するクライアントコード
- クライアントコードが忘れずにUnit of Workへの登録を呼び出す
- 新規生成時はregisterNew
- 読み込み時はregisterClean
- 更新時はregisterDirty
- 削除時はregisterDelete
- メリデメ
- メリ
- 柔軟
- 「あえて登録しない」ことで、メモリ上のオブジェクトの変更をDBに反映しないこともできる
- もっとも、これは明示的にcloneを作るべき
- 「あえて登録しない」ことで、メモリ上のオブジェクトの変更をDBに反映しないこともできる
- 柔軟
- デメ
- クライアントコード側での登録し忘れがおきる
- メリ
- object registration
- 生成されるオブジェクトが、自身をUnit of Workに登録する
- オブジェクトはUnit of Workを知っている必要がある
- どうやって渡す
- メソッドやctorの引数で引き回す
- thread-scopedのRegistry等、どこからでもアクセスできる場所に置いておく
- どうやって渡す
- メリデメ
- メリ
- クライアントコード側で、Unit of Workへの登録を忘れることはなくなる
- デメ
- オブジェクトの開発者は依然としてUnit of Workへの登録を忘れずに実装しなければならない
- コード生成やAOPの使いどころ
- オブジェクトの開発者は依然としてUnit of Workへの登録を忘れずに実装しなければならない
- メリ
- unit of work controller
- DBアクセスのControllerとしてのUnit of Work
- DBからデータを読み込むときにはUnit of Workを通す
- クライアントコードは、空のオブジェクトを生成し、Unit of Workに渡してデータを読み込ませる
- Unit of Workはオブジェクトをcopyして返す
- UPDATE時には控えのcopyと照合して、実際に変更されたフィールドのみを更新できる
- メリデメ
- メリ
- Unit of Workへの登録忘れがない
- デメ
- copyのオーバヘッド
- メリ
- 変更したオブジェクトのみcopyすることでオーバヘッドを減らせる
- Unit of Workへの登録は必要になる
- 【所感】Copy-on-Writeで回避できないかな?
- updateよりもreadが多い場合に有効
- Unit of Workへの登録は必要になる
- オブジェクトの生成について、caller registrationの検討
- 更新順
- デッドロック回避
- 全てのシステムトランザクションで同じ順序でロックを取得すること
- この管理もUnit of Workが適所
- batch update
- RDB以外のトランザクショナルリソースにいてもUnit of Workは適用可能
When to Use It
- 根本は、メモリ上オブジェクトとDB上データとの同期
- すべてをシステムトランザクションの中で行えるならば、自分が変更したオブジェクトだけを気にすればいい
- 【補】serializableならば、他のシステムトランザクションの変更から影響を受けない
- 【補】しかし、複数のリクエスト/レスポンスを含むセッション = ビジネストランザクションを丸ごとシステムトランザクションで包むのは現実的でない
- 【補】そのため、自前でビジネストランザクションを管理する必要がある
- 他のセッションによるDBへの変更を考慮しなければならない
- ビジネストランザクションのcommit時に、変更をまとめてDBに反映するUnit of Work以外の方法
- Transaction Scriptの中で、変数で管理する
- すぐ手に負えなくなる
- オブジェクトにdirty flagをもたせる
- オブジェクトグラフを走査して、dirty flagの立っているものをDBに反映する
- Domain Model採用時はオブジェクトグラフを走査するのは難しい
- ドメインオブジェクトのネットワークは単純なコレクションや木ではないため
- Transaction Scriptの中で、変数で管理する
- Unit of Workの特長は、オブジェクトの変更を一元管理すること
- 【補】コレクションとして水平に持つので走査もしやすい
- Optimistic Offline LockやPesimistic Offline Lockを適用する土台にもなる