Repository Pattern 把「怎麼存資料」抽象化了。但它解決不了一個問題:
建訂單要同時更新三個地方——訂單表、庫存表、用戶積分表。如果訂單寫成功但庫存更新失敗,資料就不一致了。這三個操作必須在同一個 transaction 裡,要嘛全成功,要嘛全回滾。
但 OrderRepository、InventoryRepository、UserRepository 各自獨立——誰來協調它們的 transaction 邊界?
這是 Unit of Work Pattern 要解決的問題。
Unit of Work 的角色
Unit of Work 做兩件事:
追蹤變更:在一個業務操作(Use Case)期間,所有對 domain object 的修改都被 UoW 記錄下來,暫時不寫進 DB。
統一提交:業務操作結束時,呼叫 unitOfWork.commit(),UoW 把所有變更包在一個 transaction 裡寫入。如果任何一步失敗,整個 transaction rollback。
// 業務操作(Application Service)
async function createOrder(command: CreateOrderCommand) {
const uow = unitOfWorkFactory.create()
const order = new Order(...)
const inventory = await uow.inventories.findById(command.productId)
inventory.reserve(command.quantity) // 只是修改記憶體裡的物件
order.addItem(inventory, command.qty) // 同上
await uow.orders.save(order) // 登記要儲存 order
await uow.inventories.save(inventory) // 登記要儲存 inventory
await uow.commit() // ← 這裡才真的寫進 DB,在同一個 transaction
}
業務邏輯不需要知道「transaction 怎麼管理」,也不需要顯式呼叫 BEGIN TRANSACTION / COMMIT——那些是 infrastructure 的細節,交給 UoW 處理。
UoW 和 Repository 的分工
Repository 負責單一 Aggregate 的存取抽象——「給我 order #123」「把這個 order 存起來」。它不知道有沒有其他操作在同一個 transaction 裡。
Unit of Work 負責一個業務操作的 transaction 邊界——它持有所有 Repository,確保它們共用同一個 DB connection / session,讓最後的 commit() 能把所有變更包在一起。
兩者的關係:UoW 管 Repository,Repository 管 Aggregate。
框架裡的 UoW
很多框架已經把 Unit of Work 內建了,只是沒有用這個名字叫它:
-
Spring
@Transactional:方法加上這個 annotation,整個方法執行期間的所有 DB 操作在同一個 transaction,方法正常結束 commit,拋例外 rollback。這就是 UoW 的概念,只是用 AOP 自動化了。 -
Entity Framework (C#):
DbContext本身就是 UoW——你操作context.Orders.Add(order),不立刻寫 DB,呼叫context.SaveChanges()才統一提交。 -
SQLAlchemy (Python):
Session物件是 UoW,用session.add()追蹤變更,session.commit()統一寫入。
知道「Unit of Work」這個名字,是為了理解這些框架在做什麼——DbContext、Session、@Transactional 背後的概念是一致的。
什麼時候需要手動實作 UoW
如果你用的框架已經提供了 UoW(Spring、EF、SQLAlchemy),通常不需要自己實作——直接用框架的 session 管理就夠了。
需要手動實作的情況是:你在 Clean Architecture 或 Hexagonal Architecture 裡,要讓 Application Service 不直接依賴框架的 session 物件(因為那會讓 application 層耦合 infrastructure)。這時你定義一個 UnitOfWork 介面在 application 層,把 commit() / rollback() 的行為抽象化,infrastructure 層再提供具體的 PostgresUnitOfWork 實作,讓框架的 session 在那裡管。
上一篇 → Repository Pattern
下一篇 → Layered Architecture