对象和数据库的天然阻抗 转摘于:http://www.jdon.com/mda/oo-reltaion2.html
在“面向对象建模与数据库建模两种分析设计方法的比较”一文中我们比较了在对需求分析时两种方法的不同,所谓数据库建模分析,就是项目一开始就根据需求建立数据库模型,如数据表结构和字段等,这种错误现象大量普遍存在我们国内项目实践中,从每年大量招聘启示中就可见一斑:招聘数据库建模人员,招聘Java面向对象程序员。这些说明软件业一边在大量使用Java/.NET/Ruby on Rails这样OO语言同时,还在同时使用与OO体系抵触的围绕关系数据库的分析设计方法。
为进一步说明OO和关系数据库是属于两个不同世界观,存在天然矛盾,就象有神论和无神论,就象水与火那样属于截然相反的两种编程知识。正好最近TheServerSide刊登一篇大谈对象数据库ODBMS的文章:When to use an Embedded ODBMS(以下简称ODBMS一文)
http://www.theserverside.com/tt/articles/article.tss?l=EmbeddedODBMS
这篇文章不但谈到了OO和关系数据库天然阻抗;谈到了ODBMS和RDBMS区别,也谈到了ODBMS和O/R Mapping如Hibernate的区别,甚至谈到了ODBMS在非C/S如嵌入式方面的优点。这篇文章我看最重要价值就是它用大量篇幅阐述了对象和关系数据库存在的天然矛盾,我这里就将这部分篇幅大意转载这里,可以说是经过我咀嚼后反馈的结果,版权思想还是属于这篇文章,我这里只是用中国人更易于接受方式把这个天然矛盾转述出来:
对象和关系数据库累赘转换
在一个面向对象系统中,数据存在于对象中,在关系数据库中,数据存在于数据表的记录中。
在关系数据库世界中,我们必须掌握表结构、表记录等概念,这里面没有任何对象概念,当我们在OO语言中使用关系数据库时,因为在OO世界中是大量对象,所以必须将数据在这两个不同世界之间转换传输。
这就导致了大量垃圾临时对象,增加了应用系统的复杂性。这也是我们很多人使用了Java等这样的OO系统后,反而觉得开发效率并没有OO宣传那么高的原因, 说白了,OO思想没有完全占领应用系统,因为有关系数据库盘踞着数据库这个最后堡垒负隅顽抗。
下面看看我们程序如何为了让OO语言和关系数据库捆绑在一起工作,如何弥补两个世界的裂缝,如何在他们之间和稀泥。 为了将对象保存到关系数据库中,我们必须将对象中的数据解散开来,再将它们组装到SQL中,然后执行SQL。
一个类如下:
| public class Course { public string name; public int courseID; int deptID; public int creditHours; } |
将上述对象保存到关系数据库的SQL语句如下:
| PreparedStatement insertStatement = connection.prepareStatement( "INSERT INTO Courses (name, courseID, deptID, creditHourse) " + "VALUES (?, ?, ?, ?)"); insertStatement.setString(1, course.name); insertStatement.setInt(2, course.courseID); insertStatement.setInt(3, course.deprtID); insertStatement.setInt(4, course.creditHours); insertStatement.executeUpdate(); |
上述在两个世界之间做的翻译工作与复杂性取决于对象Course这样的复杂性。如果Course字段有十几个,那么这个保存SQL将更复杂。
更重要的是,万一有一个字段发生变化,更改量就很大。我们不但要修改对象,而且还要修改数据表结构,有过数据库编程经验的人知道,如果表中有数据,表结构变动带来的问题可能就象噩梦一样,所以,我们程序员经常以这个需要更改表结构拒绝一些软件的维护和拓展,这其实更是错上加错;在ODBMS一文中提出了对象数据库解决方案:只要更改类结构,其他都有ODBMS搞定;使用ORM如Hibernate也只多一个步骤:更改映射配置。
继承关系的尴尬实现
对象和关系数据库的不匹配还表现在关系数据库难以实现对象世界中的继承关系,如下图:

这是一个典型的对象世界表达客观世界的类图,学生和教授都是人,都具备人一些共性,当然他们之间也有区别,所以我们用上述继承关系来表达这样一个情况。
那么如果这样继承关系的类图如何保存到关系数据库中呢?有两种方式:one-class-per-table(一个类对应一个表)和one-object-per-row(一个对象对应一个表行)。
在one-class-per-table方式中,Student对象放在Student表中,Professor放在Professor表中。但是Student和Professor实际具有共性Person,这实际上将Person这个共性对象中数据分割成两个表保存,从语义上所:也就是将一个对象分割成两个部分了;而且当你要获取这个对象时,需要两次Select。同样道理增删改查都要两次。
如果按照one-object-per-row,将这Student和Professor放到一个表中,就会产生空白字段。Student对象中数据保存到Student对象对应的字段中,那么Professor对象对应的字段就是空的,反之也然。
这些都反映了对象和关系数据库天然不匹配,两者根本就无法搭配在一起工作,只有一方作出妥协,大部分情况是对象作出妥协,这样,一个OO语言Java/.NET系统就做成了一个数据库中心系统,根本无法享受OO语言带来快捷方便,可维护性强,由于Java出现比较早,更多程序员将项目失败归结于Java语言本身,转而使用数据库思维去做.NET,去做Ruby On Rails,还是会碰到上面这些问题,没有碰到,只能说明他们系统中就没有对象概念,解决方式很简单很可笑:矛盾双方,消灭一方不久解决矛盾了。
类的复杂关系实现
下面我们再看看ODBMS一文中列举的类复杂关系如何用关系数据库实现保存:
| public class Department { private Professor[] professors; ... } |
这个Department类很明确告诉我们这样一个意思,在一个Department中,存在很多Professor,大白话就是:一个部门里有很多教授,这个类就自然准确地表达这个意思,这也体现了使用OO表达需求的自然性和方便性。
那么我们下面看看,如果我们使用关系数据库来保存Department这个对象,很显然,这里需要使用关系数据库的表外键,通过表外键来表达Department表和Professor之间1:N关系,关键问题是:这个外键一般是设计在Professor表中,这就造成语义上的误解。
对象Department表达的需求含义是:
1. 我是一个部门对象,在我里面包含很多教授对象。
当这个对象在关系数据库,由于外键在Professor表中,那么意思就是:
2. 我是一个教授对象,这里有一个我所属的部门对象。
前后对比发现,其实完全是两者不同表达方式,这已经属于拷贝走样了,当我们从关系数据库中获得Department 对象时,得按照关系数据库规则绕一个弯来获得完整的Department 对象。也就是说:每次获得一个对象Department,我们得将这个需求意思翻译成关系数据库的表达方式,这种内耗式的翻译不但容易出错,也带来了程序员开发上的负担。万一不留神,翻译出错,问题就严重了。
当然,如果我们使用ODBMS,就不必做这些费力不讨好的翻译转换,也不再绕着弯子编程,只要直接告诉ODBMS或ORM框架如Hibernate,就能够获得一个真正对象意义上的Department。
以上是TSS的ODBMS一文大量篇幅阐述了对象和关系数据库矛盾的方面,所以,我们才认为:如果你使用对象语言,如Java/.NET/Ruby On Rails等,那么就必须坚持OO思想和方法,从程序中杜绝关系数据库对软件的影响,将关系数据库只看成是活动对象的“冬眠”(英文Hibernate)地方,这也就是ORM框架Hibernate的本义所在。
对象和数据库的天然阻抗 转摘于:http://www.jdon.com/mda/oo-reltaion2.html的更多相关文章
- 使用command对象操作数据库
1.Command对象查询数据库 protected void Button1_Click(object sender, EventArgs e) { //读取web.config节点配置 strin ...
- MSSQL 2012 拒绝了对对象 'extended_properties' (数据库 'mssqlsystemresource',架构 'sys')的 SELECT 权限
查看数据库的表的时候报如下错误: MSSQL 拒绝了对对象 ) 解决方法: 在数据库里相应的用户权限中,把db_denydatareader的复选框的勾去掉.db_denydatareader是拒绝访 ...
- 拒绝了对对象 'sp_sdidebug'(数据库 'master',所有者 'dbo')的 EXECUTE 权限。
如果在调试过程中出现异常“拒绝了对对象 'sp_sdidebug'(数据库 'master',所有者 'dbo')的 EXECUTE 权限.”则可以通过以下方式解决: 打开master数据库,打开扩展 ...
- ORMBase对象/关系型数据库映射在MVC中的应用
ORM这个字眼在我们操作数据库的时候,是我们使用频率最高的.它到底是个什么东西呢,我们先来看看一些对它的含义解释. 对象/关系数据库映射(object/relational mapping(ORM)) ...
- 拒绝了对对象 'sp_OACreate' (数据库 'mssqlsystemresource',架构 'sys')的 EXECUTE 权限。
执行一个存储过程, 由于里面使用到了一些 --创建对象 EXEC sp_OACreate 'VBScript.RegExp', @objRegex OUT --设置属性 EXEC sp_OASe ...
- 集合对象与自定义javabean对象接收数据库查询的数据 (基础知识扫盲)
一.集合对象(List,Map,数组)等对象接收数据库查询的记录,如果没有一条记录,就得到的内容为空的集合,不是null: 例如:List查不到记录得到的就是size=0的list 二.自定义的jav ...
- Hibernate通过实体对象对应数据库表信息
Hibernate通过实体对象对应数据库表信息,包括:数据库表名称.主键列名.非主键列名等. 获取对象映射缓存管理类: AbstractEntityPersister aep = (AbstractE ...
- 对象关系型数据库管理系统(PostgresQL )
PostgresQL是 对象关系型数据库管理系统(ORDBMS).PostgreSQL支持大部分SQL标准并且提供了许多其他现代特性:复杂查询.外键.触发器.视图.事务完整性.MVCC.同样,Po ...
- 拒绝了对对象 'XXX' (数据库 'XXX',架构 'dbo')的 SELECT 权限
2010-04-17 23:16 在IIS里测试ASP.NET网站时会遇到这样的问题(ASP.NET+SQL2005)我自己的解决方法是这样的: 1.打开SQL2005管理界面(没有安装SQLServ ...
随机推荐
- Linux查看关闭进程
ps:进程的静态列表(Process status) - PID:进程号,每个进程独一无二的标识符(关闭进程需要使用) - TTY:终端所属,表明进程产生于哪一个终端,对于多用户使用的Linux服务器 ...
- 数据结构 java概况
数据结构可以分为三种结构: 线性结构: 数组:栈:队列:链表:哈希表 树结构: 二叉树,二分搜索树,AVL,红黑树,Treap,Splay,堆,Trie,线段树,K-D树,并查集,哈夫曼树 图结构 邻 ...
- centos7系统之telnet命令rpm包安装
centos7系统之telnet命令rpm包安装 1. 下载安装包 rpm包下载位置:http://vault.centos.org/6.3/os/x86_64/Packages/ [root@ywb ...
- linux内核启动过程
作者:严哲璟 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 通过qemu以 ...
- Sass函数:Sass Maps的函数-map-get($map,$key)
map-get($map,$key) 函数的作用是根据 $key 参数,返回 $key 在 $map 中对应的 value 值.如果 $key 不存在 $map中,将返回 null 值.此函数包括两个 ...
- 【串线篇】Mybatis之缓存原理
所谓二级缓存是名称空间级别的缓存,什么意思呢? TeacherDao.xml首行 <mapper namespace="com.atguigu.dao.TeacherDao" ...
- gensim word2vec |来自渣渣硕的学习笔记
最近写论文跑模型,要用到word2vec,但是发现自己怎么也看不懂网上的帖子,还是自己笨吧,所以就有了我的第一篇博客!!! 关于word2vec工具打算写一个系列的,当然今天这篇文章只打算写: 如何 ...
- CentOS6.5下安装jdk配置环境变量错误问题:
CentOS6.5下安装jdk,使用gedit /etc/profile 配置环境变量为如下: export JAVA_HOME=/usr/soft/jdk7export PATH=$JAVA_HO ...
- Apache Flink 的迁移之路,2 年处理效果提升 5 倍
一.背景与痛点 在 2017 年上半年以前,TalkingData 的 App Analytics 和 Game Analytics 两个产品,流式框架使用的是自研的 td-etl-framework ...
- 【Python】用python -m http.server 8888搭建本地局域网
python -m http.server 8888 由于工作中经常会用到局域网中同事之间互传文件,当文件太大时,可以采用局域网ftp之类的方式进行传输. 这里采用python的一个服务,可以快速的搭 ...