关于O/R Map的讨论(200分)

L

lsj

Unregistered / Unconfirmed
GUEST, unregistred user!
在数据库操作中最常见的就是发送一个SQL检索出所需的数据,一般传送到客户端的是原始数
据,而不是对象,所以在没有面向对象数据库支持下,我们必须自己建立一层O/R Map,将关系
数据库中的取得的大量数据转换成对象,暂且不论这个O/R Map如何建立,很可能一次就要创
建数千个(甚至更多)对象,客户端连上来的数量一多,每个都查询不同性质的数据,这样就无
法使用缓冲了,这样反复的创建对象,会对服务器造成很大的负担.而存储过程和预定义SQL
我以前用delphi的时侯做过,取来数据后,客户端还得对数据再加工抽出有用的信息,也就是
客户端得了解数据结构,不可避免地将界面和逻辑混在一起了.
总而言之,就是数据->对象的转换这一环节应找到一个合适的解决办法,否则一一映射转换带
来性能问题(我估计是性能上的问题主要是由创建对象过程及垃圾回收机制引起,对象本身所
引起的内存消耗与原始数据相比应该差不多),不转换就破坏了封装的完整性,也失去了OO的
最大优点.
请大家指正~~
 

TDataSet本身不是一个对象,
没有必要把一条记录,或一条记录中每个数据当作一个对象
 
TDataSet之类的东西只是一个数据集,以我的理解,一条记录就对应一个对象,一张表就对应一个类,而
一个数据集对应着一个表或视图
 
以前讨论过一点:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=882692
 
曹大侠,看过你的帖子了,你的那个帖子主要是围绕如何实现O/R Map的讨论的,我现在困惑的
是有没有必要做这个映射,因为我得考虑一下性能问题,你在实践中是怎么处理这个问题的?有
碰到性能问题吗?
 
这是另一位网友的意见:
也许,你需要建一个由DAO(Data Access Object) 和 VO(ValueObject) 构成的数据层.
这样对于视图逻辑,数据是经过封装的,不需要知道底层数据的存储结构,只通过 VO
和 DAO 的接口,就可以进行 CRUD(Create, Read, Update, Delete) 操作.
 
一一映射转换带
来性能问题(我估计是性能上的问题主要是由创建对象过程及垃圾回收机制引起,对象本身所
引起的内存消耗与原始数据相比应该差不多),不转换就破坏了封装的完整性,也失去了OO的
最大优点.
我的意见当然是一定要实现OR映射。不然写程序太痛苦。生不如死啊。
 
好,那我就确定下来做这个O/R Map,性能问题到最后再调整
迟点我把我的方案贴上来,还请曹大侠和各位高手指正
 
在中间加一个应用层作转换,跟三层结构一样
 
现在我对这个问题的认识还比较模糊,我的理解基本上是这样:
问题的产生是由于关系数据库对数据的存储方式与Java对象之间不匹配
解决办法:
1.将ResultSet转换成Java对象表示
优点:客户端编程是对象与对象之间的交互,降低了复杂性,隔开了客户端与数据库
缺点:ResultSet的数据量一大可能会引起性能的迅速下降(现在我还没有对此做测试,仅仅是推测)
2.将ResultSet转换成XML
优点:通用,可用XSLT转成HTML
缺点:缺乏数据操纵能力,XML的解析带来了额外的负担
现在我的应用是以查询为主,所以我打算用第2种方案
请各位多指点~~~
 
第一种方案在数据量大时的性能下降在一定程度上可以忽略的,当然这取决于你的
硬件环境,但在我这里的使用表明,性能上的下降不是很大,其实java构造一个对
象虽然慢,但如果合理的使用对象池的话,性能上还是可以保证的。
第二种方案xml的解析有可能带来令人头痛的性能问题,曹晓钢好像已经碰到了吧,
出来说两句怎么样。对于这一点,你要有充分的心理准备。
补充一下,我这里构造一个映射一千条记录的对象,时间只有几十毫秒,还包括sql
查询的时间,而且是在我开发用的破机器上,当然这是在单用户情况下,在考虑并发
的生产环境,我发现其实最大的问题在数据库并发查询上,我们作压力测试时基本上都是
数据连接池首先不足,导致系统性能下降,在连接池足够大的情况下,似乎并没有
碰到构造对象的性能瓶颈。
情况下,
 
看看这篇微软的文章:
==========================================================================
http://www.microsoft.com/china/msdn/library/dnbda/html/BOAGag.asp
设计数据层组件并在层间传递数据
==========================================================================
将关系数据映射到业务实体
实现数据访问逻辑组件
实现业务实体
事务处理
验证
异常管理
授权与安全性
部署
==========================================================================
上面提到的问题都有讨论。
 
to avant:
你推荐的文章我看了,写得很好,谢谢!
to 小猪:
现在我还不会做压力测试 :-(
现在我这里的服务器是电脑城组装的双P-III 1G,512M内存(8000多块的机器)
 
小猪,你说的很有道理啊,我帮你帖上来了 ^_^
这是原文:
基于数据库的性能分析,其实不一定要做多大的数据量,写几个性能比较差的视图,多用点
union和外连接之类的,一点点数据也可以做到比较好的效果,因为你不需要对数据库本身的
性能作测试,只是关心在作并发的复杂查询时程序本身的性能如何。我个人感觉一个耗时大约
两三秒的查询应该是比较典型的应用查询,基于这样的速度作并发时其实就会发现瓶颈通常在
于数据库的连接上而不是在作o r maping。
我这里有一个比较典型的例子,我们是作了o r maping的,出于防止超时的考虑,我们在
op层作了限制每次查询只返回不超过1000条记录,系统中有一个查询正常情况大约是返回
4000-6000条记录,但并不是简单的单表,因此查询速度是非常慢的,差不多一次查询耗时3-4秒
(在一台很破的机器上,这样便于作性能优化),我们只能是重复查询6次(或者更多,或者更少),
得到6个maping的对象,然后遍历这六个对象,构造一个新的maping对象,实际上测试的结果表明,
不管作了多少次的遍历(当然不能太多^_^),耗费的时间基本上就是一次查询时间的整数倍,基本
上没有看到因为o r maping造成的性能损失。
这里需要强调一点的是,就是那个查询,在我调试的机器上是20秒左右才能出结果,但在我们
真实的运行环境下大约是1-2秒,这跟实际环境的硬件性能是分不开的,主要是内存,基于java的
应用,内存不足带来的性能上的问题比代码带来的问题要大的多。
实际来看一下,作o r map只是需要遍历结果集一次然后生成对象,而基于xml则需要对xml文本
作多次解析,这里带来的性能上的损失是很大的,前者只需要简单的加大内存就可以在一定程度上
提升性能,而后者需要的多次解析在必然对cpu提出更高的要求。一般来说,加内存总比加cpu方便
得多,是不是?
我提到曹晓钢已经碰到了性能的问题,也是前几天跟他聊天的时候知道的,不过他的情况比较
特殊,一个1G内存的机器上又要跑db2,又要跑他们自己的应用,基于xml的解析方式便给他们带来
了麻烦,不过他们好像已经找到了一些解决办法,具体你可以向他请教一下。
我没有作过基于xml的应用,因此对使用xml来作数据映射在性能上究竟如何没有具体的概念,
我只是想说一点的就是基于o r maping只要设计合理,是不会有太大的性能上的问题的。
 
no ,no.我的情况中xml是作为一种通用的树型结构的。实践证明XSLT性能实在是不高。除了使用client
side XSLT(就是现在delphibbs使用的这种方法)以外,只能够利用xalan自己的方式把一个XSLT翻译成
java class,(好像叫translet),然后用它来直接处理XSLT,效率应该会快很多。我说应该,是因为实际上
我没有做这一部优化,我觉得我们现在的性能已经不错了。如果随着使用人数增加,我是会考虑这样使用的。
XSLT还有一个问题就是消耗内存非常多。O/R mapping是基于比较简单的JDBC的,内存消耗很小,而XSLT却是
一个很复杂的过程,解析,处理的复杂度远远超过简单直接的JDBC O/R mapping. 所以使用server side XML会
给服务器带来很大的影响。
总之来说,如果你的应用本身依赖于XML,比如你的系统的输出就是一个XML,(web service?)或者基于xml的报表,
或者你对XML已经非常精通,完全可以控制它的性能,否则会带来很大的痛苦。
从这个角度上来说,yysun使用client side XSLT,真的是非常好,利用了XML减少了网络流量,降低了服务器负载,
还标准化了各个叶面的结构,是非常成功的。而且client端XSLT做的也很成功,效率不算低。
 
关于O/R Map这个问题真是越想越有意思.我原来对这个问题的认识仅仅是数据库的每一列
数据对应着某个类的一个属性,这样我只是将结果集中的数据简单的做一一映射.这样我的
代码很简单--多表关系我是用视图处理,基本是单表映射.撇开是否使用视图不论,我的
做法是自己写SQL,实际上我做的是Resultset(Rowset)->对象的映射,而且还只是用于查询.
所以我没有考虑到并发的问题.也就是说CRUD四个基本操作我并没有封装在一个对象中.
当我试图完整封装这四个基本操作时,我发现自己的代码迅速的膨胀起来,而且出错了.
现在我只是在做单个表->单个类的映射,但假如我们是要构建一个复杂的系统,有许多对象,
而且具有继承结构时,我担心代码的复杂度会大大增加,如果仅仅是一个对象的转换就要写
很多的代码,那构建复杂一点的系统时,这个O/R转换层将带来很大的工作量.
各位是如何做O/R Map的呢?
 
首先,单一resultset <->单一类集合还是比较容易的。 复杂系统无论在怎么复杂,两个具有联系
的表之间无非是1;1, 1:N,N:N的关系。只要实现了这三种关系,什么事情都好办了。
A:B=1:1,很简单,你在你的类B里面另外再加一个方法: B.getInstance(A),得到从A到B的映射
或者B.getA(),从B的当前instance得到B;
A:B=1:N, 这是一个master/detail关系。 A 应该具有类似于如下的方法: A.getBCollection();
得到B从属于A的collection;
B则有:B.getAInstance(),从B的实例得到A.
A:B=N:N, 应该A和B都有A.getBCollection()的方法。
根据需要,程序员可以自行决定是否实现进一步的映射。比如你从数据库中得到A的一个实例的时候,如果
A:B=1:1,那么你可能希望直接把B融合到A中去,或者自动执行A中一个internal load B的操作,把B
作为一个内部成员也load到内存中来。但是假如A:B=1:N,那么是否执行自动加载B就要慎重对待。一不小心
就会带来严重的性能问题。假如B:C也是1:N,那么如果二者都是自动加载,内存中会出现指数级的增量风暴,
后果很严重。Castor的JDO据说就存在这样的问题。
 
其实ejb的模型在这方面做的不错,可是性能上的问题我一直没有
解决,据说其实ejb性能并不差,看来是我自己掌握的不好了,也没办法。
我们目前做的东西在某种程度上参照了ejb的模型,不过对于上面曹晓钢提到的
多表之间的映射关系,我们基本上还是由程序员自行实现的,在基本框架模型
中并没有考虑这个东西,因为反正也做不了多好,做了用处也不大,还不如不做。
 
我认为对于多对多的关系是数据库设计的问题,而且,根据数据库原理来说,多对多是尽量要避免得
一般都用1对多代替,或者中间价格连接表,所以对于OR/MAPPING主要应该考虑1对1和1对多的关系,
曹说的1对多这个问题,我也遇到过,就是要多次调用实例,这样性能会下降很快
 
顶部