首页/开发/系统分析与架构设计速查/工作单元(Unit of Work)
架构风格与模式58 条

工作单元(Unit of Work)

跟踪一次业务操作期间的对象变更,在提交时统一计算变更集并写入数据库,保证事务边界清晰且减少重复写操作;常与仓储、标识映射配合使用。

工作单元是什么

工作单元(Unit of Work)在一次业务操作期间跟踪对象的增删改,把变更暂存在内存里,到提交时统一计算变更集并写入数据库。它的两个直接收益是:事务边界由业务用例显式界定,而不是散落在各处的 save 调用里;同一对象的多次修改合并成一次写入,减少数据库往返。它常与仓储(负责存取)和标识映射(保证同一记录对应同一对象实例)配合使用。

基本信息

职责记录新增/修改/删除,事务提交时统一持久化
配合模式仓储(存取)、标识映射(同一对象同一实例)
收益事务边界明确,减少数据库往返
边界一个工作单元对应一个业务用例,不跨越用户交互的等待时间

典型使用场景

  • 下单流程:订单、订单行、库存扣减在一个事务内统一提交
  • 批量导入:累积若干条记录后按批提交,控制事务大小与内存占用
  • 领域模型持久化:对象图在内存中修改,提交时由变更跟踪生成 SQL
  • 审计与事件发布:提交时把审计记录与领域事件一起落库,保证与业务变更同事务
  • 测试替身:用内存实现替换数据库,验证业务逻辑而不依赖真实库

提交时机示意(伪代码)

提交时机示意(伪代码)
uow = new UnitOfWork()
order = repo.find(1)
order.addLine(item)      // 跟踪修改
repo.save(order)
uow.commit()             // 统一计算变更集并写库
// 业务失败:uow.rollback(),不产生部分写入

常见实现方式

方式机制注意
显式登记代码显式 registerNew/registerDirty最清晰但样板代码多
变更跟踪代理框架代理对象记录属性变化对象必须由仓储返回才被跟踪
脏检查快照提交前对比对象快照差异内存开销大,大对象图需谨慎
ORM 会话会话即工作单元,如 ORM 的 Session 或 EntityManager会话生命周期与事务边界容易混淆

使用要点

  • 工作单元的生命周期与业务用例对齐:请求开始创建、请求结束提交或回滚
  • 把审计记录与领域事件放进同一个工作单元,避免业务成功但事件丢失
  • 绕过工作单元的直接写库操作会让变更跟踪与审计丢失,需要在代码评审中阻止
  • 批量任务要分批提交:单个工作单元过大时内存与锁持有时间都会失控
工作单元跨越过长的业务流程会长时间占用事务与连接,应保持短事务;把“等待用户确认”之类的环节放在事务外,用状态字段而不是未提交的数据库事务来表达中间状态。
工作单元不等于“数据库事务”:它描述的是内存中的变更集合与提交时机,最终是否使用数据库事务、用到什么隔离级别,仍是单独的设计决定。

易错点

  • 工作单元与业务事务生命周期不一致,出现长事务锁等待,高峰期连接被占满
  • 绕过工作单元直接写库,变更跟踪与审计记录丢失,数据来源无法解释
  • 单个工作单元承载批量任务的全部数据,内存占用与事务时长同步膨胀
  • 变更跟踪依赖对象由仓储返回:手工 new 出来的对象不会被跟踪,修改静默丢失
  • 提交时才发现并发冲突,缺少版本号或悲观锁策略,只能整单失败重来

数据来源与参考

  • Martin Fowler《Patterns of Enterprise Application Architecture》
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌