关系数据库映射(行为模式之工作单元)
[问题域]
正常情况下,如果使用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)