Java,Beans和关系数据库的镜像(1)

发表于:2007-07-14来源:作者:点击数: 标签:
Java ,Beans和关系数据库的镜像(1) · 摘要 JDK1.1包括了新的数据库存取(JDBC)及组件(JavaBeans)的应用程序接口(APIs)。这两个API结合在一起,可用来开发通用数据库代码。通过用唯一的一个类去存取任何一种JDBC数据库(封装于不同组件中的各个应用程序有着
Java,Beans和关系数据库的镜像(1)

· 摘要

JDK1.1包括了新的数据库存取(JDBC)及组件(JavaBeans)的应用程序接口(APIs)。这两个API结合在一起,可用来开发通用数据库代码。通过用唯一的一个类去存取任何一种JDBC数据库(封装于不同组件中的各个应用程序有着其具体的编码),用户就不必因为数据库结构一点点的细小变化去修改数据库编码。

一个关系数据库基本上包括一系列相互关连的表,在每一个表中存有一类与应用系统相关的数据。例如一个地址簿数据库中,可能有关于人员、住址、电话号码等方面的表。

在数据库中,每一个这样的实体将被作为一系列的字符串,整数及其它原始数据类型存贮起来。数据库中,表的定义将描述每一种与实体相关的信息如何在一个表的字段中存储。

例如,你可以在一个名为“人”的表中,有两个字段别表示所存字符串为“姓”和“名”。每一张表应当有一个或几个字段值作为标识,确保每条记录的唯一性。

这些标识或“键”可以用来连接存在于不同表中的信息。例如你可以在“人员”表中,为每个人指定唯一的“人员号码”的键值,并在“地址”表
中的相应字段中使用同一个键值。这样,你可以通过对两个表中的“人员号码”字段值的匹配,使每一个人和他的地址关联起来。

关系数据库系统出现于七十年代,时至今日,它仍然是存储巨量数据的主要方式。因而,Java软件工具有必要具备处理关系数据库的能力。

关系数据库要想被某个Java应用程序利用,首先需要解决两个问题。

第一:需要某些基础的中间件来建立与数据库的连接,向数据库发出SQL查询等等;
第二:操纵数据库的处理结果要与操纵任何一种Java信息一样方便——作为一个对象。前一个问题已被SUN及几个数据库产商解决;后一个问题
则有待我们进一步去探究。

在为普通的程序开发业务定义大量的APIs这项工作上,SUN一直保持着与许多软件公司的合作关系。在JDK1.1APIs中,JDBC的API是最早建立起来的。而且,它已得

到了为数众多的应用。这些应用中,有的是100%的纯Java,有的则是Java和其它程序的混合体,如:用现有的ODBC数据源进行连接(参看图1)。Java Soft已将一个

关于现有的JDBC驱动程序的介绍放在它的Web站点上(http://splash.javasoft.com/jdbc/jdbc.drivers.html)。

非常明显,这些应用的优缺点取决于你的环境和设置,在此我不准备对它们的各种情况进行逐一论述。在下面的内容中,我们假定,在你的机器中已拥有某种Java

开发环境,并且你已正确地安装并测试过某个JDBC驱动程序,或者运用过某种JDBC驱动程序及SUN的JDBC/ODBC桥。

· JDBCAPI

JDBCAPI作为一个单独的Java包(或类库,即java.sql)出现,包括有一系列的类。这些类提供了处理某个关系数据库的中
间件。本质上讲,它们使得你可以关联某个数据库,并向其发出查询。你可以对这些查询结果进行处理,检索你数据库的meta-信息(meta-information),并且处理

在此间可能发生的各种异常情况。

让我们来看一个简单的JDBC例子,看一看应用了JavaJDBC之后,查询会得到怎样的简化。表1是一个极其简单的数据库。在清单1中的编码是一段最简单的对关系数据库进行SQL查询所需的Java语句。

人员#名姓
43674SandorSpruit
90329JohnDoe
65435DonaldDuck
Stringur1="jdbc:odbc:sample";
Stringquery="SELECT*FROMPERSON";
booleanmore;
try
{
Class.forName("sun.jdbc.odbc.jdbcOdbcDriver");
Connectioncon=DriverManager.getConnection(ur1,"sandor","guest");
Statementstmt=con.createStatement();
ResultSetrs=stmt.executeQuery(query);
While(more=rs,next())
{
intnumber=rs.getInt("PERSON#");
StringfirstName=rs.getString("FIRST_NAME");
StringlastName=rs.getString("LAST_NAME");
System.out.printIn(number+""+firstName+""+lastName);
}
rs.close();
stmt.close();
con.close();
}
catch(SQLExceptionex)
{
ex.printStackTrace();
}

· 清单1:一个应用了JDBC的SQL查询

这段编码的含义是:先装入SUN的JDBC/ODBC驱动程序,然后与被jdbc:odbc:sample指定的数据库建立起一个关联,最后对该
数据库进行一个简单的SELECT查询。如果没有遇到查询异常(SQLException),程序将循环地从结果集(ResultSet)中每次抽出一条
数据库记录,并将其显示在屏幕上。好了,现在我们来看一看这段程序还有哪些不足?在清单1的这类程序中,存在着两个根本性的错误:

1.这种编码用到了数量众多的数据库meta-信息,而这些信息都只能手工编码到程序中。当你想要取一个数值时,你必须提前知道你将取到的数值是一个整数、浮

点数、还是一个双精度数。这将会使得编写一个可以处理任何一个数据库的类变得十分困难;并且每一个数据库的细小调整都会逼你去仔细地检查和修改程序。

2.数据库中的信息总是作为一个单个的RecordSet(记录集)实例来传递,而这种实例并不是一个真正的对象。RecordSet类(与其它的数据库类封装没什么差别)更象

一个指针或游标,借助方法,它能够提供存取数据信息的途径。RecordSet中的实例实际上并不包括信息,它们仅仅表示获得信息的方式
。这正说明了当你要调用另外的RecordSet方法去获取某些真实的数据信息的时候,你必须通过RecordSet去做更多的工作(利用RecordSet.NEXT()去移动指针)。实际上,JDBC类的确仅仅传递这类联系松散的字段。即使你完全了解数据库的所有内部细节,这也没有任何价值,因为在Java提供了存储和处理信息的方法。

所以,理想的状态是,有一种好的方法,能够逐一地从数据库中抽取记录或字段(通过RecordSet),并且将取到的信息“填”入到新生成的对象之中。这一解决方式

的关键在于关系数据库(RDB)和面向对象的数据模型(ODB)之间的相似性。RDB中的表和ODB中的类的作用很相似,而记录和对象也有着某些相同的属性。你可以

将记录看作是用来初始化某个对象的数据元素的数据组。如果你已将记录从数据库中抽取出来,就必须调用类构造函数来生成上面所说的对象。若能够将每一条记录自动地传到适当的构造函数中,就可以轻而易举地由记录来构造对象。

在开发一个小的应用程序时,有可能将每一个记录传递给某个构造函数,以此来生成新的对象。你可以经常利用对象参照来操纵从数据库中抽取的任何数据。因为

你通过RecordSet所得到的每一个对象最终都是java.lang.Object的扩充。你可以定义一个BibClass,使其具有各类的共同属性,BigClass类操作将利用Javainstanc

eof算子来实时决定运行中所遇到的数据库信息,并且通过一个大的switch选择,跳到相应的程序段中。

你也可以定义一个相似的带有多个构造函数的BigClass,每个构造函数有差别不太大的调用参数。你可以用BigClass(int,int),BigClass(int,float)等等,取

决于你从RecordSet中循环取出的数据的类型(这一方法当然将会包括许多冗余代码)。然而,以上两种方法都不能真正解决问题。因为记录和构造函数在程序中的关系仍将是僵硬的。若想得到通用的数据库编码,必须自动地建立数据库和构造函数二者的关联。Java的性能对于此时的我们就如雪中送碳。清单2中的程序片段只需一个类名就可以建造一个Java类。这样,我们就可以凭借类和表的名称来识别那些可以处理从表中抽取出的记录的构造函数。利用标准的JDBC类,可以容易地获得

所有表的表名,在此,我们将要充分利用这个Java小技巧。只要简单地为每个数据库表开辟一个Java类,使类名和表名相互匹配,无论何时,每当从表中抽取出一条记录的时候,通过将表名传递给Class.forName(),程序将自动生成一个对象。

原文转自:http://www.ltesting.net