关系数据库映射(行为模式之工作单元)


[问题域]

正常情况下,如果使用Data Mapper解决了Domain对象和数据库分离的目的,使用时,如果每当一个Domain对象创建、修改或删除时,最简单的方式就是立即对数据库进行更新操作,但是这样会对数据库产生大量的调用动作。如果不这样做,就必须记录下Domain对象的各种修改动作,以保证最后提交时,对数据库进行相应的更新,保持Domain对象和数据库的一致性。

[解决方案]


找一个处所保存Domain对象的各种变化,最后提交时,就知道应该要做什么修改,并最终写入数据库。而这个处所可以称之为工作单元(Unit of work),使用这种方式被命令为工作单元模式(参考[Martin Fowler企业架构模式])。


工作单元模式(Unit of work)

根据以上描述可知,工作单元模式包括两个主要方面:

1. 记录操作过的各种Domain对象
2. 同步到数据库中





我们先来看看如何记录操作过的各种Domain对象


1.由调用者注册。比如:调用者创建一个Domain对象时,同时通知工作单元,执行了更新操作。

  缺点:有程序开发者主动控制,人是最靠不住的。
  有点:可以主动决定是否注册,(也就是决定把Domain更改是否写入数据库)

2.由Domain对象注册。
比如:Domain对象中的Create方法中比如加入通知工作单元的代码,工作单元可以作为参数传入,或者固定的地方可以获取(如ThreadLocal保存)。

  缺点:也是需要由人在各个Domain对象的各种操作中加入固定通知工作单元代码。
  优点:当然具有一致性,同时就可以采用AOP的思想统一操作(比如Proxy,Minxin等)

3.工作单元控制器。
总的思路是,工作单元控制所有的读操作,读取对象的时候,对它进行注册为Clean的,并产生一个拷贝,提交时,对比一下哪些字段进行了改变,然后再更新。对于不想拷贝的对象则需要主动进行注册。(TOPLink使用此方式)

  缺点:不需要拷贝的对象需要主动注册,否则一律拷贝一个。
  优点:对Domain对象的改变只进行了有选择的更新。


接下来讨论工作单元同步到数据库的问题:

1.更新顺序

如果数据库允许,只在事务提交时检查引用完整性,而不是每次SQL都检查,则随便怎么用都可以。如果数据库不允许,则在工作单元中则根据元数据(metadata)指定的顺序执行更新数据库的操作。

2.批量更新

如果有一些列的更新,删除或新增操作,则可以在工作单元中,作为一个单条语句发送请求。


[结论]

工作单元最大的好处就是把各种复杂的操作保存在一个固定的地方。这种模式可以应用于所谓有类似需求的地方。


参考资料:


Patterns of Enterprise Application Architecture (author:Martin Fowler)