Qi4j和NoSql运动

09-09-29 banq
                   

24日一篇Qi4j and the NoSQL movement文章开始谈Evans DDD和数据库的关系,指出如何使用对象替代关系数据库设计。

JavaZone 2009 第二个介绍就是"På tide å kaste ut relasjonsdataben"(Is it time to throw out the

relational database? 是时候扔掉关系数据库了?),这是为替代关系数据库寻找替代物。

作者总结说:,它发现更多人使用关系数据库其实在做下面四件事情:存储对象storing objects, 查询这些对象querying them, 报表reports, 和备份 backups。关系数据库只擅长报表,其他都是垃圾,对象和关系数据不匹配object-relational impedance mismatch 是大家都知道,Evans DDD难以使用OR mapping映射实现是大家的共识。

在Qi4j中有显式SPI 支持用来存储和查询对象,彼此是分离的,存储对象使用EntityStore实现,查询对象用EntityFinder 实现, 查询上比SQL更加面向对象。

实体建模

将实体的职责分离到不同限定场景 bounded contexts,比如订单中有OrderItemId, OrderId, ProductId 和 Qty,这是合乎逻辑的最初订单,后来有 MinDeliveryQty 和 PendingQty字段,是和订单交货有关,这其实是两个概念,订单和订单的交货,但是我们把这些字段都混合在一个类中了。这就是一件坏事情。

在Qi4j中,不是把实体看成铁板一块,一开始就把它分解到各种场景,下订单和订单交货交付是两个场景,它们应该有彼此独立的接口,由实体来实现,这就能够让实体和很多场景打交道,而彼此不影响,这就是组合模型composite model的一个关键优点。所有这些场景都是有mixin接口实现,在数据库中它们是一个,也就是说,从ER模型上看,它们是一个整体,但是从domain model领域模型角度看,它们是分离的。

看到这里,本人也非常有体会,下面是两张是我本人基于Jdon框架开发JiveJdon是设计,短消息模型和关注模型有不同的实现之类,在数据库模型中,它们在一张表,但是在业务层领域层,它们是不同的实现,也决定表现层有不同的处理方式。

关系在设计时就被定义

如果你使用key-value 来存储对象,比如在Qi4j中,一旦你设计好实体模型,对象之间的关联关系和属性将自动存储,无需任何配置和设置,这极大地降低需要设计一个实体模型的时间,因为所有的与关系数据库的映射模式和处理开销就消失了。

在Qi4j是没有让实体有递归引用问题, EntityStore 将为你自动处理一切,如果你需要存储复杂的值,那么它们将被序列号成JSON字符串,存储在一个字段中,有人认为领域模型信息将倾向于扩散到整个应用,特别是进入数据库,Qi4j使用entity definition在一个模型中完成全部定义,使用EntityStore 自动保存模型的数据,这样这个扩散问题就迎刃而解。

职责改变

程序员负责模型的改变,而DBA则负责在数据库中实现它,DBA有职责 保持着所有的应用程序访问相同的数据库,并确保他们在被修改后,继续之前的存储轨道。

如果领域模型以key-value驻留在应用中(我的理解就是领域模型保存在内存缓存中),报告和整合是基于领域模型的事件(在Jdon框架6.1版本中,推出异步观察者事件,主要就是实现基于领域模型的事件),应用程序将变得更加易于修改,而且不相互影响。

该文作者还对更多数据库概念在Qi4j中处理实现方法做了解释,使用Qi4j数据库自动生成,无需定义Schemas,如果你想直接访问数据,那有多少框架能够方便让你直接访问Key-value中的数据?

关于Joins 和 queries,Key-value存储是不支持的,这里key-value存储主要是指Mongo和Couch之类新式数据库,作者认为他们就不应该支持Joins 和 queries,这些都是业务层来实现,比如使用Qi4j的RDF store,通过和key-value存储结合,可以获得惊人的加载和存储性能,可以使用各种技术优化,这里我理解为使用分布式缓存如terrracotta来提升性能。

关于Datatypes数据类型,对于Qi4j来说,如果数据库支持 Long or Date类型,就使用,否则就是要String字符串型字段,或者使用base64 encoding序列化保存,有人担心性能,因为有缓存,第一次加载性能可以忽略不计了。

还有关于key-value不支持Aggregation,作者认为这些和报表有关,而报表是不应该在key-value存储中实现,这是SQL强项。

总结:Qi4j + key-value存储数据库(Mongo和Couch)是一种更加符合DDD的架构。

[该贴被admin于2009-09-30 16:07修改过]

[该贴被admin于2010-03-15 16:48修改过]

[该贴被admin于2010-03-15 16:48修改过]

                   

4
banq
2009-09-29 16:02

相关讨论:

忘记Scala,Qi4J是下一个 Java?

xmuzyu
2009-09-29 20:39

RDBMS是完全面向数据的,已经失去了业务意义,而key-value可以理解为面向业务的存储,所以只有面向业务的存储加上面向业务的内存计算才是合适的组合方式,将面向数据的存储(RDBMS)加上面向业务的计算(具体来说就是通过DDD建模以后的对象模型进行运算)就不能很好的配合工作,即使它们配合了,也需要很多额外的工作,这样势必会产生矛盾。因此key-value是一种更加符合业务的存储,划分边界以后,将聚合根通过key-value存储,计算的时候,通过key直接拿到聚合根进行内存运算,这样系统在性能的两个方向(“多大”和“多快”)上都会得到很大的提升。

snow0613
2009-09-30 11:15

banq大大,根据您的推荐,有去看了下Qi4j。下了些例子看,可是貌似没有它内部实现的源码,难道这个不是开源的吗?

PS:我个人的习惯是,碰到问题,就去看程序的源码,所以很强烈地希望能看到这个东东的源码。

banq
2009-09-30 16:10

应该是开源的,看协议是源码支持apache的,不过只是看到使用JDK,大概处于手忙脚乱阶段。

不过估计Qi4j源码将是相当琐碎的代码,它只是一个组合器,业务领域层框架不像表现层和持久层框架,有时要看看源码。