|
摘要:
SQL Server
ODBC
Standard Security:"Driver={SQL Server};Server=Aron1;Database=pubs;Uid=sa;Pwd=asdasd;"
Trusted connection:"Driver={SQL S... 阅读全文
数据库连接大全下面罗列了各种数据库使用JDBC连接的方式,可以作为一个手册使用。 1、Oracle8/8i/9i数据库(thin模式) Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库的SID String user="test"; String password="test"; Connection conn= DriverManager.getConnection(url,user,password);
2、DB2数据库 Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance(); String url="jdbc:db2://localhost:5000/sample"; //sample为你的数据库名 String user="admin"; String password=""; Connection conn= DriverManager.getConnection(url,user,password);
3、Sql Server7.0/2000数据库 Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance(); String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb"; //mydb为数据库 String user="sa"; String password=""; Connection conn= DriverManager.getConnection(url,user,password);
4、Sybase数据库 Class.forName("com.sybase.jdbc.SybDriver").newInstance(); String url =" jdbc:sybase:Tds:localhost:5007/myDB";//myDB为你的数据库名 Properties sysProps = System.getProperties(); SysProps.put("user","userid"); SysProps.put("password","user_password"); Connection conn= DriverManager.getConnection(url, SysProps);
5、Informix数据库 Class.forName("com.informix.jdbc.IfxDriver").newInstance(); String url = "jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER=myserver; user=testuser;password=testpassword"; //myDB为数据库名 Connection conn= DriverManager.getConnection(url);
6、MySQL数据库 Class.forName("org.gjt.mm.mysql.Driver").newInstance(); String url ="jdbc:mysql://localhost/myDB?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1" //myDB为数据库名 Connection conn= DriverManager.getConnection(url);
7、PostgreSQL数据库 Class.forName("org.postgresql.Driver").newInstance(); String url ="jdbc:postgresql://localhost/myDB" //myDB为数据库名 String user="myuser"; String password="mypassword"; Connection conn= DriverManager.getConnection(url,user,password);
8、access数据库直连用ODBC的 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ; String url="jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};DBQ="+application.getRealPath("/Data/ReportDemo.mdb"); Connection conn = DriverManager.getConnection(url,"",""); Statement stmtNew=conn.createStatement() ;
大型Java Web系统选型问题探讨
字体:大 中 小 发布于: 2007-9-19 23:25:28 | 分类: java技术
一位ID是jackson1225的网友在JavaEye询问了一个大型Web系统的架构和部署选型问题,希望能提高现有的基于Java的 Web应用的服务能力。由于架构模式和部署调优一直是Java社区的热门话题,这个问题引发了很多热心网友的讨论,其中一些意见对其它大型Web项目也有很好的指导意义。在讨论之初jackson1225这样描述了当前的应用的架构和部署方案:
目前系统架构如下:
web层采用struts+tomcat实现,整个系统采用20多台web服务器,其负载均衡采用硬件F5来实现; 中间层采用无状态会话Bean+DAO+helper类来实现,共3台weblogic服务器,部署有多个EJB,其负载均衡也采用F5来实现; 数据库层的操作是自己写的通用类实现的,两台ORACLE数据库服务器,分别存放用户信息和业务数据;一台SQL SERVER数据库,是第三方的业务数据信息; web层调用EJB远程接口来访问中间件层。web层首先通过一个XML配置文件中配置的EJB接口信息来调用相应的EJB远程接口;
该系统中一次操作涉及到两个ORACLE库以及一个SQL SERVER库的访问和操作,即有三个数据库连接,在一个事务中完成。
这样的架构其实很多公司都在使用,因为Struts和Tomcat分别是最流行的Java Web MVC框架和Servlet容器,而F5公司的负载均衡是横向扩展常见的解决方案(例如配置session sticky方案)。由于这个系统中有跨数据源的事务,所以使用Weblogic Server EJB容器和支持两阶段提交的数据库驱动就可以保证跨数据源的事物完整性(当然,容器管理的分布式事务并非是唯一和最优的解决方案)。
但是随着Rod Johnson重量级的著作《J2EE Development without EJB》和其中的Spring框架的流行,轻量级框架和轻量级容器的概念已经深入人心。所以对于jackson1225提出的这个场景,大多数网友都提出了置疑,认为这个系统滥用了技术,完全是在浪费钱。网友们大都认为SLSB(无状态会话Bean)完全没有必要出现在这个场景中,认为SLSB通过远程接口访问本地资源会有很大的性能开销,这种观点也是Rod johnson在without EJB中批判EJB 2.x中的一大反模式。
由于JavaEE是一个以模式见长的解决方案,模式和架构在JavaEE中占有很重要的地位,所以很多业内专家也都警惕“反模式(Anti-patterns)”的出现。对于上面所述的方案是否是反模式,jackson1225马上站出来申辩:
我们项目就是把EJB作为一个Facade,只是提供给WEB层调用的远程接口,而且只用了无状态会话Bean,所以性能上还可以的。
这个解释很快得到了一些网友的认可,但是大家很快意识到架构的好坏决定于是否能够满足用户的需求,davexin(可能是jackson1225的同事)描述了这个系统的用户和并发情况:
现在有用户4000万,马上要和另一个公司的会员系统合并,加起来一共有9000万用户。数据量单表中有一亿条以上的数据。这是基本的情况,其实我觉得现在的架构还是可以的,现在支持的并发大概5000并发用户左右,接下来会进行系统改造,目标支持1万个并发用户。
具体的并发量公布后又有网友置疑这个数据,认为这个系统的Servlet容器支持的并发数太小,怀疑是否配置不够优化。davexin又补充了该项目的服务器配置:
系统前端tomcat都是用的刀片,配置在2G内存,cpu大概在2.0G,每台机器也就支持250-400个并发,再多的话,就会相应时间非常的常,超过20秒,失去了意义,所以我们才得出这样的结论的。
一位ID是cauherk的网友提出了比较中肯的意见,他没有从Web容器单纯的并发支持能力上提出改进方案,而是提出了对于类似的应用的一些通用的改进提示,这里摘要一下:
数据库压力问题 可以按照业务、区域等等特性对数据库进行配置,可以考虑分库、使用rac、分区、分表等等策略,确保数据库能正常的进行交易。
事务问题 要在两个数据库中操作,那么必须考虑到分布式事务。你应该仔细的设计你的系统,来避免使用分布式事务,以避免分布式事务带来更多的数据库压力和其它问题。推荐你采用延迟提交的策略(并不保证数据的完整),来避免分布式事务的问题,毕竟commit失败的几率很低。
web的优化 将静态、图片独立使用不同的服务器,对于常态的静态文件,采用E-TAG或者客户端缓存, google很多就是这样干的。对于热点的功能,考虑使用完全装载到内存,保证绝对的响应速度,对于需要频繁访问的热点数据,采用集中缓存(多个可以采用负载均衡),减轻数据库的压力。
对于几乎除二进制文件,都应该在L4上配置基于硬件的压缩方案,减少网络的流量。提高用户使用的感知。
网络问题 可以考虑采用镜像、多路网络接入、基于DNS的负载均衡。如果有足够的投资,可以采用CDN(内容分发网),减轻你的服务器压力。
cauherk的这个分析比较到位,其中ETags的方案是最近的一个热点,InfoQ的“使用ETags减少Web应用带宽和负载”里面对这种方案有很详细的介绍。一般以数据库为中心的Web应用的性能瓶颈都在数据库上,所以cauherk把数据库和事务问题放到了前两位来讨论。但是davexin解释在所讨论的这个项目中数据库并非瓶颈:
我们的压力不在数据库层,在web层和F5。 当高峰的时候,F5也被点死了,就是每秒点击超过30万,web动态部分根本承受不了。根据我们程序记录,20台web最多承受5000个并发,如果再多,tomcat就不响应了。就像死了一样。
这个回复让接下来的讨论都集中于Web容器的性能优化,但是JavaEye站长robbin发表了自己的意见,将话题引回了这个项目的架构本身:
performance tuning最重要的就是定位瓶颈在哪里,以及瓶颈是怎么产生的。
我的推测是瓶颈还是出在EJB远程方法调用上!
tomcat上面的java应用要通过EJB远程方法调用,来访问weblogic上面的无状态SessionBean,这样的远程方法调用一般都在 100ms~500ms级别,或者更多。而如果没有远程方法调用,即使大量采用spring的动态反射,一次完整的web请求处理在本地JVM内部的完成时间一般也不过20ms而已。一次web请求需要过长的执行时间,就会导致servlet线程被占用更多的时间,从而无法及时响应更多的后续请求。
如果这个推测是成立的话,那么我的建议就是既然你没有用到分布式事务,那么就干脆去掉EJB。weblogic也可以全部撤掉,业务层使用spring取代EJB,不要搞分布式架构,在每个tomcat实例上面部署一个完整的分层结构。
另外在高并发情况下,apache处理静态资源也很耗内存和CPU,可以考虑用轻量级web server如lighttpd/litespeed/nginx取代之。
robbin的推断得到了网友们的支持,davexin也认同robbin的看法,但是他解释说公司认为放弃SLSB存在风险,所以公司倾向于通过将 Tomcat替换为Weblogic Server 10来提升系统的用户支撑能力。robbin则马上批评了这种做法:
坦白说我还从来没有听说过大规模互联网应用使用EJB的先例。为什么大规模互联网应用不能用EJB,其实就是因为EJB性能太差,用了EJB几乎必然出现性能障碍。
web容器的性能说到底无非就是Servlet线程调度能力而已,Tomcat不像WebLogic那样附加n多管理功能,跑得快很正常。对比测试一下 WebLogic的数据库连接池和C3P0连接池的性能也会发现类似的结论,C3P0可要比WebLogic的连接池快好几倍了。这不是说 WebLogic性能不好,只不过weblogic要实现更多的功能,所以在单一的速度方面就会牺牲很多东西。
以我的经验来判断,使用tomcat5.5以上的版本,配置apr支持,进行必要的tuning,使用BEA JRockit JVM的话,在你们目前的刀片上面,支撑500个并发完全是可以做到的。结合你们目前20个刀片的硬件,那么达到1万并发是没问题的。当然这样做的前提是必须扔掉EJB,并置web层和业务层在同一个JVM内部。
接下来robbin还针对davexin对话题中的应用分别在tomcat和weblogic上的测试数据进行了分析:
引用: 2。1台weblogic10 Express(相当于1台tomcat,用于发布jsp应用)加1台weblogic10(发布ejb应用),能支持1000个并发用户...... ...... 4。1台tomcat4.1加1台weblogic8,只能支持350个并发用户,tomcat就连结超时,说明此种结构瓶颈在tomcat。
这说明瓶颈还不在EJB远程调用上,但是问题已经逐渐清楚了。为什么weblogic充当web容器发起远程EJB调用的时候可以支撑1000个并发,但是tomcat只能到350个?只有两个可能的原因:
你的tomcat没有配置好,严重影响了性能表现 tomcat和weblogic之间的接口出了问题 接着springside项目发起者江南白衣也提出了一个总体的优化指导:
1.基础配置优化
tomcat 6? tomcat参数调优? JRockit JVM? JVM参数调优? Apache+Squid 处理静态内容?
2.业务层优化
部分功能本地化,而不调remote session bean? 异步提交操作,JMS? cache热点数据?
3.展示层优化
动态页面发布为静态页面? Cache部分动态页面内容?
davexin在调整了Tomcat配置后应验了robbin对tomcat配置问题的质疑,davexin这样描述经过配置优化以后的测试结果:
经过测试,并发人数是可以达到像robbin所说的一样,能够在600人左右,如果压到并发700人,就有15%左右的失败,虽然在调整上面参数之后,并发人数上去了,但是在同样的时间内所完成的事务数量下降了10%左右,并且响应时间延迟了1秒左右,但从整体上来说,牺牲一点事务吞吐量和响应时间,并发人数能够提高500,觉得还是值得的。
至此这个话题有了一个比较好的结果。这个话题并非完全针对一个具体的项目才有意义,更重要的是在分析和讨论问题的过程中网友们解决问题的思路,尤其是cauherk、robbin、江南白衣等几位网友提出的意见可以让广大Java Web项目开发者了解到中、大型项目所需要考虑的架构和部署所需要考虑的关键问题,也消除了很多人对轻量Servlet容器与EJB容器性能的一些误解。
ADO 来自ITwiki,开放的中文IT百科 Jump to: navigation, <jumptoSearch> 微软公司的ADO (ActiveX Data Objects) 是一个用于存取数据源的COM组件。它提供了编程语言和统一数据访问方式OLE DB的一个中间层。允许开发人员编写访问数据的代码而不用关心数据库是如何实现的,而只用关心到数据库的连接。访问数据库的时候,关于SQL的知识不是必要的,但是特定数据库支持的SQL命令仍可以通过ADO中的命令对象来执行。
ADO被设计来继承微软早期的数据访问对象层,包括RDO (Remote Data Objects) 和DAO(Data Access Objects)。ADO在1996年冬被发布。
ADO包含一些顶层的对象:
连接,代表到数据库的连接 记录集,代表数据库记录的一个集合 命令,代表一个SQL命令 记录,代表数据的一个集合 流,代表数据的顺序集合 错误,代表数据库访问中产生的意外 字段,代表一个数据库字段 参数,代表一个SQL参数 属性,保存对象的信息 ADO组件的使用需要利用支持COM的高级语言,例如ASP中的VBScript或者Visual Basic,甚至Delphi,微软的竞争对手Borland的一个产品,现在也支持使用ADO来访问数据库。
在新的编程框架.NET Framework中, 微软也提供了一个面向Internet的版本的ADO,称为ADO.NET。其对象模型和传统ADO差别很大。
DAO
DAO(Database Access Object)使用Microsoft Jet数据库引擎来访问数据库。Microsoft Jet为象Access和Visual Basic这样的产品提供了数据引擎。
与ODBC一样,DAO提供了一组API供编程使用。MFC也提供了一组DAO类,封装了底层的API,从而大大简化了程序的开发。利用MFC的DAO类,用户可以编写独立于DBMS的应用程序。
DAO是从Visual C++4.0版开始引入的。一般地讲,DAO类提供了比ODBC类更广泛的支持。一方面,只要有ODBC驱动程序,使用Microsoft Jet的DAO就可以访问ODBC数据源。另一方面,由于DAO是基于Microsoft Jet引擎的,因而在访问Access数据库(即*.MDB文件)时具有很好的性能。
DAO和ODBC的相似之处
DAO类与ODBC类相比具有很多相似之处,这主要有下面几点:
二者都支持对各种ODBC数据源的访问。虽然二者使用的数据引擎不同,但都可以满足用户编写独立于DBMS的应用程序的要求。
DAO提供了与ODBC功能相似的MFC类。例如,DAO的CDaoDatabase类对应ODBC的CDatabase类,CDaoRecordset对应CRecordset,CDaoRecordView对应CRecordView,CDaoException对应CDBException。这些对应的类功能相似,它们的大部分成员函数都是相同的。
AppWizard和ClassWizard对使用DAO和ODBC对象的应用程序提供了类似的支持。
由于DAO和ODBC类的许多方面都比较相似,因此只要用户掌握了ODBC,就很容易学会使用DAO。实际上,用户可以很轻松地把数据库应用程序从ODBC移植到DAO。
Visual C++随盘提供了一个名为DaoEnrol的例子,该例实际上是Enroll的一个DAO版本。读者可以打开DaoEnrol工程看一看,它的源代码与Enroll的极为相似。读者可以按照建立Enroll的步骤来建立DaoEnrol,其中只有若干个地方有差别,这主要有以下几点:
选取的数据源不同。在用AppWizard创建DaoEnrol时,以及在用ClassWizard创建CDaoRecordset类的派生类时,在Database Options对话框中应该选择DAO而不是ODBC。而且DAO的数据源是通过选择一个.MDB文件来指定的,即点击“...”按钮后在文件对话框中选择要访问的.MDB文件。
记录集的缺省类型不同。ODBC记录集的缺省类型是快照(Snapshot),而DAO则是动态集(Dynaset)。
参数化的方式不同。DAO记录集的m_strFilter和m_strSort中的参数不是“?”号,而是一个有意义的参数名。例如,在下面的过滤器中有一个名为CourseIDParam的参数。 m_pSet->m_strFilter ="CourseID = CourseIDParam"; 在DoFieldExchange函数中,有下面两行: pFX->SetFieldType(CDaoFieldExchange::param); DFX_Text(pFX, _T("CourseIDParam"), m_strCourseIDParam); DFX函数的第二个参数也是CourseIDParam。
处理异常的方式不同。例如,在删除记录时,对异常的处理如下所示:
try
{
m_pSet->Delete();
}
catch(CDaoException* e)
{
AfxMessageBox(e->
m_pErrorInfo->m_strDescription);
e->Delete();
}
除了上述差别外,AppWizard和ClassWizard也隐藏了一些细微的不同之处,例如,DAO记录集是使用是DFX数据交换机制(DAO record field exchange)而不是RFX,在DAO记录集的DoFieldExchange中使用的是DFX函数而不是RFX函数。
10.8.3 DAO的特色
DAO可以通过ODBC驱动程序访问ODBC数据源。但DAO是基于Microsoft Jet引擎的,通过该引擎,DAO可以直接访问Access、FoxPro、dBASE、Paradox、Excel和Lotus WK等数据库。CDaoDatabase类可以直接与这些数据库进行连接,而不必在ODBC管理器中注册DSN。例如,下面的代码用来打开一个FoxPro数据库:
CDaoDatabase daoDb;
daoDb.Open( “”,FALSE,FALSE,"FoxPro 2.5;DATABASE=c:\\zyf");
CDaoDatabase::Open函数用来连接某个数据库,该函数的声明为:
virtual void Open( LPCTSTR lpszName, BOOL bExclusive = FALSE, BOOL bReadOnly = FALSE, LPCTSTR lpszConnect = _T("") ); throw( CDaoException, CMemoryException );参考资料: http://www.czvc.com/tech/Visual%20C++JC/chap10_8.htm裡面都有介紹
补充:
ado和dao的区别 |
http://www.itisedu.com 2006-4-17 11:08:11 中科永联 |
[关键字]ADO DAO ODBC |
ADO:Active数据对象(ActiveDataobjects):ADO实际是一种提供访问各种数据类型的连接机制。ADO设计为一种极简单的格式,通过ODBC的方法同数据库接口。可以使用任何一种ODBC数据源,即不止适合于SQLServer、ORACLE、AccESs等数据库应用程序,也适合于Excel表格、文本文件、图形文件和无格式的数据文件。ADO是基于OLE-DB之上的技术,因此ADO通过其内部的属性和方法提供统一的数据访问接口方法。 DAO:数据访问对象(DataAccessObjECts):是一种面向对象的界面接口。通过DAO/Jet功能可以访问ISAM数据库,使用DAO/ODBCDIrect功能可以实现远程RDO功能。使用DAO的程序编码非常简单,DAO提供丰富的游标(Cursor)类型的结果集和非游标(Cursor-Less)类型的结果集,同DDL(数据描述语言)的功能很类似。 现在vb数据库编程大都使用ADO,很少人还用DAO.
DAO是集合,对象,方法和属性;它用对象集合来处理数据库,表,视图和索引等。使用DAO编程,可以访问并操作数据库,管理数据库的对象和定义数据库的结构等。
ADO是类似于DAO和RDO的面向对象的数据库访问技术。DAO是第一个面向对象的接口,它显露了miCROSoft Jet数据库引擎,并允许VB开发者通过ODBC直接连接到其他数据库一样,直接连接到access表。DAO适合单系统应用程序或小范围本地分布使用。
ADO是DAO/RDO的后继产品,它扩展了DAO和RDO所使用的对象模型,这以为着它包含较少的对象,更多的属性,方法(和参数),以及事件。ADO当前并不支持DAO的所有功能,它主要包括RDO风格的功能性,以便和OLE DB数据源交互,另外还包括远程和DHTML技术。
|
JDO之前世今生
|
2007-04-13 来源:www.javaresearch.org 作者:未知 |
(本文转自《CSDN开发高手》2003第10期)
1 Java与数据库应用,JDBC
Java发明以来,在短短的几年之间,迅速占领了从桌面应用(J2SE)到服务器(J2EE),再到小型设备嵌入式系统(J2ME)的应用开发市场,其语言吸取了SmallTalk的一切皆对象的理念,摆脱了C++的历史累赘,简洁、自由的风格赢得了很多开发者的喜爱。从JDK1.1开始,Java成为实用的语言,而不是被人观望的新品秀;再经过JDK1.2的大量增强(尤其是Collection Framework),JDK1.3的虚拟机效率提升(HotSpot),JDK1.4的融合百家之长(Logging、RegExp、NewIO等),现在已经是成熟稳重,颇显大家风范。 在企业级市场上,大部分的应用建立在数据库基础上,数据是企业的生命,传统开发语言,包括面向过程的C、面向对象的C++、变种Pascal的Delphi(非常棒的语言,我用过四年),面向数据的PowerBuilder等等,先后在数据库开发的舞台上展现风姿。Java当然不会放过这些,于是,出现了JDBC。在JDBC的帮助下,Java也迅速渗入数据库开发的市场,尤其是面向企业服务器的应用开发。 今天要谈的JDO,与JDBC有非常密切的关系,尽管JDO并不是只面向JDBC的数据对象包装规范。下面先简单地介绍一下JDBC。
1.1 关系数据库之百家争鸣,ODBC
关系数据库的历史一言难尽,我只能从我的接触经历和所见所闻,简单地叙述一下。最早的时候,计算机还只在一些大型的研究机关露面,并不是普罗大众可以涉及的。苹果电脑将个人电脑引入民间,再随着IBM的PC标准开放,个人电脑逐步普及开来,加上微软的DOS操作系统,以及Borland的Turbo系列语言开发环境,老百姓发现原来电脑可以做这么多事!后来,出现了DBASE,一个简单的关系数据库系统,和SQL语言。后来,Borland看到了数据库的市场前景,推出了Paradox(也是当今Delphi和C++Builder中仍然使用的Paradox),一举占领了民用数据库的大部分江山,之后,Borland干脆收购了Dbase,后来又购买了InterBase,将数据库市场的领先优势一直保持到Windows3.0出现。这时候,微软在Windows1.0和2.0被人痛骂之后顽强地推出3.0,以及更稳定的3.1和Win32API,造就了个人电脑桌面操作系统的霸主地位,在Borland未警觉的情况下,购买了同样具有类Dbase数据库技术的Fox公司,并迅速将其易用化,形成了FoxBase,后来演变成FoxPro,逐渐超过了Borland,成为个人电脑数据库的大户。微软再接再励,为简单易用而低负荷要求的数据库应用开发了Access,赢得了广大开发人员的心。当然,同期的Oracle、Sybase、Informix等商用数据库凭专注于企业级数据库技术成为高端的几位领军人物。微软当然也想成为高端数据库供应商之一,于是自行开发一套面向企业级应用的数据库,不过很快项目夭折,微软不甘心,购买了Sybase的底层TDS技术,包装成了SQL Server,凭微软的高度易用性的特点,也占领了不少市场。 当市场上出现众多的数据库产品之后,Borland和微软都发现自己拥有的数据库产品挺多,市场也不小,不同的产品给用户带来不同的配置任务,不利于所有产品的推广,于是,两者纷纷开始制定数据库访问的规范,微软推出了ODBC,其面向开发人员的亲和性,逐步获得了认可,同时,Borland纠集了IBM和Novell也推出了IDAPI数据库接口规范,也就是今天BDE的核心,不过后来Novell和IBM先后退出,只剩Borland独力支撑。不过Borland是一个技术实力雄厚的公司,其技术一向领先于微软,BDE的性能比初期的ODBC不知道要好多少倍,后来微软偷师学艺,把连接池等技术加到ODBC中,在Delphi3.0及其BDE在市场上风光无限的时候,逐步赶了上来并有超过。直到今天,BDE仍是Borland的产品线上的数据库访问标准,而微软如果不是将ODBC和多数数据库的客户端内嵌进Windows的话,估计BDE仍是市场的赢家。不过,微软是玩弄市场的老手,通过对操作系统的垄断,其数据库产品和ODBC标准终究占据了多数开发市场。
1.2 从optional pack到JDK的标准API
Java开始涉及数据库应用后,Sun就极力制定Java的数据库规范,JDBC API就是类似ODBC一样,对数据库访问的底层协议进行最基本的包装,然后形成一套统一的数据访问接口,数据库连接、SQL语句句柄、结果集,都带有ODBC的影子。以方便配置为目的,Sun极力推荐完全瘦客户端的TYPE 4型JDBC驱动,这是一个不需要安装数据库客户端的驱动规范,是现在使用最多的。当然,为了保持与旧的数据库兼容,JDBC规范中包括了专用于连接ODBC的TYPE 1驱动和需要安装数据库客户端的TYPE 2驱动,以及可以由厂商在数据库服务端专门提供面向JDBC的服务的TYPE 3驱动。 JDBC最早出现时,还不属于标准JDK的一部分,而是作为一个额外包提供下载。后来,随着Java编写的数据库应用的的增多,和JDBC规范本身的逐渐成熟,JDBC终于成为JDK1.1的一部分。 JDBC目前最新的是3.0版本,还有正在讨论中的4.0版本。实际上,在开发中使用得最多的还是1.0中的API,2.0中主要增加了可双向滚动的结果集、更新批处理等提高可用性和性能的API,3.0主要增加了连接池、可更新的结果集等特性。4.0将在可管理性、连接池规范化等方面再做改进。
2 面向对象与数据库
现在的程序员,没有不知道面向对象的。作为接近真实客观世界的开发概念,面向对象使程序代码更易读、设计更合理。在普遍存在的数据库应用领域,开发人员对面向对象的追求从未停止过。从八十年代开始,就有很多公司和研究机构在进行着面向对象与数据库结合的研究。
2.1 SmallTalk、C与C++、Delphi?DObject Pascal、Java
面向对象的语言最早有好几种雏形,IBM的SmallTalk是其中最为流行的,在SmallTalk中,一切都是对象,一切都是类,它将面向对象的概念发挥到了极致。面向对象的编程比起传统的面向过程的方式挺进了一大步,使人们认识到:原来软件可以这样写。不过,由于计算机基本结构与底层硬件体系和系统软件的限制,SmallTalk还不能在理想的性能前提下推广到普通的应用上,这一点暂时限制了SmallTalk的发展,接着,C语言的面向对象版C++出现了,由于使用C语言的人很多,C++很快成为面向对象编程的主流语言。不过,为了保证与C的兼容,C++保留了很多面向过程的痕迹,比如恶心的指针、全局变量等等。Pascal的改进版Object Pascal相对来说安全许多,后来Borland干脆将Object Pascal换了个名字,叫Delphi,从此开创了一片面向对象编程的新世界, Delphi的严谨语法和快速编译吸引了众多的应用开发者,加上Borland的完美的VCL组件体系,比起MFC来方便而容易,另外,Delphi完整的数据库组件,也将数据库开发变得简单而容易,Delphi再次成为成熟的面向对象开发语言。微软当然不会放过这些,通过将MFC内置到操作系统中,微软的VC++也抢回一些市场。这也是为什么Delphi开发的应用程序编译后会比VC、VB开发的程序大的原因。 1995年,Sun的一个开发小组本来为了小型嵌入式系统开发OAK语言,结果无心插柳柳成荫,发展出了Java语言,它是一个完全摆脱了传统语言的各种负担的面向对象的语言,当然,也保留了一些非面向对象的核心(原始类型)以保证速度。现在Java也为最流行的面向对象语言之一。当然,微软同样不会放过它,擅于模仿的微软立即弄出一个C#来与之竞争,并在C#中保留了一些变种的指针(指代)以吸引传统的C开发者。关于这些语言的各自特点,这里就不一一赘述了。
2.2 数据库与数据对象化
数据库是企业级应用不可缺少的,因此,在面向对象流行的时候,数据库厂商也在进行着数据对象化的研究。这些研究在上个世纪八十年代就初现端倪。 数据库的对象化一般有两个方向:一个是在主流的关系数据库的基础上加入对象化特征,使之提供面向对象的服务,但访问语言还是基于SQL;另一个方向就是彻底抛弃关系数据库,用全新的面向对象的概念来设计数据库,这就是对象数据库ODBMS。
2.2.1 关系数据库对象化、SQL99与JDBC3.0
随着许多关系数据库厂商开始提供对象化服务,各自的接口开始互不兼容,在经历一些麻烦之后,关系数据库厂商感觉到规范化的必要,因为当初关系数据库雄霸天下时SQL92标准起了很大作用,大家可以按照统一的编程方式来访问高性能的商用数据库。 关系数据库厂商集中起来,重新将对象化服务规范起来,形成了SQL99规范,将其中的对象结构等内容规范起来,开始一个崭新的面向对象的关系数据库(ORDBMS)的历程。 JDBC3.0就是在这种情况下出台的,它将对关系数据库中的对象服务的访问API规范起来,为Java平台提供了访问ORDBMS的标准方式。当然,JDBC3.0对传统的SQL操作也进行了很多功能增强。 Oracle是一个传统的关系数据库厂商,在对象化的道路上,Oracle当然采取追加对象化特征的道路,以侵入数据对象化的市场,保持Oracle在数据库领域的领导地位。如果说Oracle7.4使Oracle走向全盛的话,从Oracle8开始,Oracle就成为关系数据库加对象类型的先驱。在Oracle8中,我们可以定义一些数据结构(Record),将普通的类型包装在其中成为数据元素,然后可以在客户端按Record结构进行访问,初步提供了面向对象的数据库服务。
2.2.2 对象数据库
对象数据库就是采用全新的面向对象概念来设计数据库的全新数据库类型。在这方面,主要以一些大学研究机构进行设计和开发,有些也形成了产品,不过由于市场方面的原因(主要是关系数据库的容易上手和市场绝对领导地位)和ODBMS先天的一些弱点(比如查询引擎很难优化),使ODBMS没有象关系数据库那样流行起来。 不过对象数据库的对象化特点还是令人割舍不下,目前还是有一些很好的产品在市场上,从商用的到免费的都用。目前在ODBMS领域占据领导地位的是Versant、FastObjects和ObjectStore等几大厂商,并且,市场份额也在逐步扩展。免费的产品包括C++编写的Ozone、纯Java的db4o等等。还有一些研究机构开发一些底层的面向对象数据库引擎,但只提供一些底层的API,不提供管理方面的功能,以及一些算法提供开放式接口,让厂商去选择和实现。比如美国威斯康新大学计算机系数据库组的SHORE引擎,就是一个非常出色的面向对象数据库引擎,现在还在积极的更新中,一些其它研究机构和数据库厂商采用它完成了自己的特别的对象数据库,比如专用于地理信息的数据库、专用于宇宙空间数据研究的数据库等等。 目前对象数据库最大的障碍是缺乏统一的规范,各个数据库厂商有各自的访问接口。对象数据库比起关系数据库来,不只是基本的几种数据类型那么简单,它还涉及继承处理、多态等一大堆面向对象特征的实现,规范化道路当然困难重重。这也是对象数据库无法普及的一个重要原因。 也有一些机构提出了一些建议的规范,比如制定Corba标准的OMG小组的一个分组ODMG提出的ODMG规范,目前已经是3.0版本,其中的OQL对象查询语言相当具有吸引力。还有一些中立的机构提出了其它的一些标准化的对象访问API,也可算是面向对象数据库的规范之一。象前面提到的FastObjects和Ozone就是符合ODMG3.0规范的。
3 Java对象映射
话说回来,在一般的开发人员眼中,数据库就是指关系数据库,因此,很多应用还是采用简单的JDBC来访问数据库。在开发的过程中,大家逐渐感觉到JDBC的局限性,比如调用复杂、容易产生资源泄漏等等,与面向对象的Java语言有一段距离,因此,很多开发小组开始思考如何将应用中的数据进行对象化建模,然后再想办法与JDBC结合起来,这就是Java数据库开发中的层出不穷的对象包装技术。
3.1 对象包装技术
3.1.1 传统包装与演变
传统包装顾名思义,就是最初出现的包装方式,很多公司都经历过这一步,产生了很多风格各异的包装方法。当然,笔者也有过还算丰富的尝试过程。 举例来说,如果我们有一个用户类: public class User { public int userId; public String name; public java.util.Date birthday; } 我们可以将其当作一个简单的数据类,然后写一些工具方法来实现与JDBC的交互。这些方法,我们可以放到一个另外的工具类中,也可以放到User类中作为静态方法。这些方法包括简单的增、删、改、查(以Oracle为例): public class User { public int userId; public String name; public java.util.Date birthday;
public static User addUser(String name, Date birthday) throws SQLException { Connection conn = …; //获取一个JDBC连接 PreparedStatement ps = conn.prepareStatement(“…”); // 获取一个序列值来作为用户标识 ResultSet rs = ps.executeQuery(); rs.next(); User user = new User(); user.userId = rs.getInt(1); //读取序列值为新用户标识 user.name = name; user.birthday = birthday; ps = conn.prepareStatement(“insert into ….”); //插入用户数据记录的SQL ps.setInt(1,user.id); ps.setString(2,user.name); ps.setDate(3,user.birthday); ps.executeUpdate(); rs.close(); ps.close(); conn.close(); return user; }
public static void deleteUser(int userId) throws SQLException { Connection conn = ….; //… }
public static User getById(int userId) throws SQLException { //… }
//… }
以上就是一个简单的数据包装的基本雏形,我们可以看到,这是一个非常简单的JDBC包装,一些代码可以模块化,以实现重用。另外,这段代码还有很大隐患,就是中途如果出现异常的话,就会使系统出现JDBC资源漏洞,因为JDBC分配的资源(conn,ps,rs等)是不能被Java虚拟机的垃圾回收机制回收的。因此,我们的addUser方法就需要改成下面的样子: public static User addUser(String name, Date birthday) throws SQLException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; User user = new User(); try { conn = …; //获取一个JDBC连接 ps = conn.prepareStatement(“…”); // 获取一个序列值来作为用户标识 rs = ps.executeQuery(); rs.next(); user.userId = rs.getInt(1); //读取序列值为新用户标识 user.name = name; user.birthday = birthday; ps = conn.prepareStatement(“insert into ….”); //插入用户数据记录的SQL ps.setInt(1,user.id); ps.setString(2,user.name); ps.setDate(3,user.birthday); ps.executeUpdate(); } finally { //这里注意一定要按照创建的顺序关闭JDBC资源: if(rs != null) try { rs.close(); } catch(SQLException ex) { ex.printStackTrace(); } if(ps != null) try { ps.close(); } catch(SQLException ex) { ex.printStackTrace(); } if(conn != null) try { conn.close(); } catch(SQLException ex) { ex.printStackTrace(); } } return user; }
所有的数据库访问方法都必须进行这样的包装,当我们的数据类达到一定的数量后(比如十几个,几十个),这些方法占据了大量的代码,维护困难、出现BUG机会增多,并且不易排错,尤其是资源漏洞这种容易引起服务器稳定性问题的BUG。 为了保持数据类的纯洁,我们可以将JDBC操作方法集中到一个公共工具类中去完成,这样,这个工具类会非常庞大,但每个数据类会变得很简单,这种方式,可以称作是DataAccessObject模式,相当于EJB中的ValueObject,是脱离数据库细节的纯对象模型。 这些都是最基本的存储处理,在基本增删改查(这里的查指按关键字查找对象)的基础上,我们还需要进行复杂的匹配查询(SQL),这使得我们的存储处理代码进一步复杂化。简单地,我们可以写一个类似的方法: public static Collection findBy(String sql) throws SQLException { //… (这里获取JDBC连接) Collection col = new Vector(); ps = conn.prepareStatement(sql); rs = ps.executeQuery(); while(rs.next()) { User user = new User(); user.userId = rs.getInt(1); user.name = rs.getString(2); user.birthday = rs.getDate(3); col.add(user); } return col; //… (同前,这里是清理JDBC资源的代码) } 这就是一个查询接口的基本定义,查询采用的语言仍是SQL。 如果我们需要将参数从SQL串中独立出来以节省数据库的解析时间并规范化,我们还需要将查询条件作为参数传递到这个方法中去,方法的接口改为: public static Collection findBy(String sql, Object[] params) throws SQLException { //… ps = conn.prepareStatement(sql); for(int i = 0; i < params.length; i++) ps.setObject(i+1,params[i]); //… } 调用的时候sql参数中会包含一些“?”号,如: select ID,NAME,BIRTHDAY from USER where … = ? and … > ? and … 当然,也有一些开发团队喜欢将所有可能的查询都写死成一个个的专用查询方法,在其中完成对应的SQL操作,这一点类似于EJBQL,只不过是将EJBQL中容器实现的功能通过手工编码来实现。这样做使得查询受到限制,但可以提供更保险的接口。 还有一些开发人员看到每个类中写这样一些查询方法使得这个类的代码变得庞大,维护麻烦,便将所有的查询方法放到一个公共的工具类中去,只是在方法中再加入一个参数:Class cls来表示需要查询哪个对象,使得每个数据类变得紧凑一些。当然,这样的结果是那个公共类变得异常庞大,谁维护谁倒霉,可以说是牺牲一人,幸福团队。不过如果这个人心理素质不够好、压力承受能力不强的话,一些对数据类的改动可能会受到他的阻碍,这时候就是“一夫当关,万夫莫开”。
现在,我们已经实现了基本对象的包装,现在才能开始考虑更多的问题。首先,我们可能会从规范化的角度出发,给每一个属性加上读写访问器getter/setter,在前面的User类中,可能我们会将基本属性部分写为: public class User { private int userId; private String name; private Date birthday;
//以下是针对以上属性的getter/setter,一般可以用IDE工具生成 public int getUserId() { return userId; } public void setUserId(int value) { userId = value; } public String getName() { return name; } public void setName(String value) { name = value; } public Date getBirthday() { return birthday; } public void setBirthday(Date value) { birthday = value};
//… }
这样,一个比较规范的数据类包装就算完成了。 另外,我们知道,面向对象概念中,一个属性可以是另一个对象,也就是说,对象之间是存在着引用关系的,这种关系还分为一对一、一对多、多对多等几种情况。从一个既定对象出发,其某个属性可以是另一个对象,也可以是包含另一组对象的集合。那么,在我们的数据包装里面,当然最好也能方便地处理对象之间的关系。假定现在我们又有一个数据类Group: public class Group { public int grouId; public String groupName; public Set users; //set of User } 这里为了简单表明含义,暂不采用getter/setter。 而User对所属的Group有一个引用: public Group belongTo; 在这里,User.belongTo和Group.users就是一个一对多的关系。 在我们的数据类中,如何才能实现数据库的存取呢?就算是不考虑Group.users这个反向关系,光是User.belongTo就是一件头疼的事。如果我们在取出一个User对象时同时将其Group对象也取出来,可以保证不会在访问某个用户的组时得到一个null。不过这样有几个缺点: 1. 数据类的存取处理(JDBC)变得复杂,需要执行很多SQL读取才行,有时候只需要访问User的基本属性时浪费时间和资源;尤其是对集合型属性的预读取,更加可怕 2. 如果按这个逻辑,双向的关系处理变得危险,很容易陷入死循环,如果要避免,必须在类代码中加入一些特别的机制,也是很麻烦的事 3. 如果对象之间的关系是更复杂的情况下,比如三个、四个对象之间互相关联,那就是一场噩梦,对代码的编写和维护都异常艰难
于是,很多开发人员自然而然地退后一步,在User类中只保留一个groupId,并不保存Group对象,这样,可以将User.belongTo属性变成int类型,而另外写一个getter方法: public Group getBelongTo() { return Group.findById(belongTo); }
而在Group类中,干脆将users属性去掉,只保留一个方法: public Set getUsers() { return new HashSet(User.findBy(“select … from USER where BELONG_TO=?”,new Object[]{ new Integer(groupId) })); } 也许细心一点的读者已经看出来了,这里的几个方法都没有将SQLException捕捉,也没有在方法中声明,也就是说是有语法错误的,因为SQLException不是一个RuntimeException。不错,确实是这样,不过我们这里为了简单明了起见,省掉这些处理,以更直接清楚地表达意思。
这样,实际上,我们的对象关系包装已经名存实亡,在类的内部有很多用于访问所引用对象的复杂代码,这些已经违背了我们将对象关系保持的初衷。有些开发人员甚至不在类中保留访问关系对象的方法,而是在客户调用时再去访问另一对象类的读取方法,如: … User user = User.getById(…); //对user对象进行一些访问,如显示其姓名等等 Group group = Group.findById(user.belongTo); //对group对象进行一些访问,如显示组名等等 …
在这样的代码里,实际上我们已经从根本上退回了关系数据库的出发点,这与直接访问数据表有多大区别呢?只不过是在表上面套了一层貌似面向对象的皮而已。不幸的是,这种方式还存在于很多应用之中。
从前面提到的这些面向对象包装的细节问题,我们可以看到这种传统包装方式的一些主要的缺陷:
3.1.1.1 数据库命名与对象设计命名的一致性问题 很多时候,我们兴致勃勃地设计好一个类图,并且经过评审之后,开始对它进行数据库包装,这时候,发现有些属性名在具体的数据库中与该数据库的关键字冲突,不能用作表名或字段名,必须在数据表设计时采用另外的名称,或者很麻烦地加上引号来使用。于是,写数据库处理代码的人有意见了,他必须很清楚地记得一个属性在类中是什么属性名,在表中又是什么字段名,在编写的类逐渐增多后,尤其是一个类经过历次变动之后,或者经过很长时间又需要改动,并去处理这些JDBC代码时,代码维护人员简单要发疯了!
3.1.1.2 对象的查询仍局限于SQL这一点也是这种简单的包装方法最不能摆脱关系数据库的地方。上面也已经说过,一些命名冲突带来了很多维护工作量,代码中必须还保留数据表的命名体系,而不是对象类的命名体系。这将使调用人员仍需要清楚记得两套命名体系,无论时间经过多久,或者开发人员是否有流动。 此外,对于普遍需要用到的连表查询,也给应用开发带来困难,这些地方仍不能突破SQL的限制。
3.1.1.3 SQL资源占用多 在处理对象集合访问或者处理集合类型属性时,往往我们只能在同一个Connection中处理一切事务,这就要求一次性地将集合中的对象全部读入,如果集合很大的话,容易造成数据库拥塞,使得性能大打折扣,适得其反。这方面的优化也是很多开发人员一直在努力改进的。
3.1.1.4 对象关系处理复杂 前面提过,对象之间的关系处理上,普通的包装技术是一种表面上的处理,在访问时调用者仍需要用大量的代码进行处理,并且,这还只是读取,在写入关系属性时会有更多的细节问题需要处理。
3.1.1.5 面向对象特色只能应用一小部分 面向对象的包装到前面所说的为止,都还只是很基本的处理,而面向对象的精华:继承和多态,在这里得不到任何帮助。我们放弃了很多合理的设计来迁就数据库的包装。
以上就是基本数据包装的主要缺陷,还有更多的小问题也需要额外的处理。 不过,有责任心的开发人员当然不会就此善罢甘休,他们冥思苦想,可能会用更好的方式来实现对象之间关系的处理,而且还会加入一些延迟访问的机制,将对象之间的引用在需要用的时候才去连接数据库取数据,另外,在类的继承上,他们也试图去在数据库包装上得到体现。 值得感谢的是,一些富有经验的团队在经历若干改进之后,毫不吝惜将他们的成果贡献出来,并将其独立化,成为可复用的组件。这也就是后来出现的对象包装产品,包括商用的和免费的。
3.1.2 产品化包装中间件
面向对象的包装产品化后,逐步推广开来,称作关系/对象映射:O/R Mapping。并且,在产品化的过程中,产品提供者在产品中逐渐提供了更多的功能。先是一些自动命名转换器得以应用,将客户代码中的类名、属性名在内部处理的时候自动地转换到对应的数据库结构命名空间上,这样,应用开发的时候不再关心具体的数据库结构,不再需要记忆不同地命名体系,只需要一心一意地根据类图来进行开发。在此之后,这些O/R Mapping产品的开发团队又向前迈了一大步:引入了词法分析器,提供面向对象的查询语言!很多对象关系的查询使应用开发变得非常方便,使O/R Mapping产品上了一个新的台阶。
3.1.2.1 TopLink TopLink是一个非常早期的产品,最初面向C++,后来也实现了Java的映射。TopLink性能优异,功能强大,并且提供了独特的查询过滤器机制,以及对关系的处理和查询都非常有效,于是,TopLink逐渐从商用化O/R Mapping产品中胜出,成为市场上的最出色的映射产品。也正因为这一点,最大的关系数据库厂商Oracle将其收购,成为提供最强数据库和最强对象映射中间件的厂商。
3.1.2.2 Castor、Hibernate TopLink虽然强大,但太强大的东西免不了得意忘形,TopLink开始将用户锁死到自己的产品上,查询方式是最突出的。它的查询体系含有很多别扭的概念(在我看来是如此),但为达到一般O/R产品不能达到的功能,开发者只能接受这些。慢慢地,也产生积怨,再加上其高昂的价格,让很多新老用户望而却步。于是,免费的产品开始崛起。 免费的O/R Mapping工具有很多种,这里只提其中最有影响力的两种:Castor和Hibernate。 Castor是Exolab组织开发的面向Java的包装工具,它最大的特色就是实现了大部分的ODMG OQL规范,在查询上,可以象完全使用一个对象数据库一样类图进行查询(后面会有介绍)。它的原理是通过Java反射API去实现属性的设置和读取。不过由于各种原因,Castor后来的版本更新越来越慢,最终停步在1.0之前,成为至今未出到1.0正式版的O/R Mapping产品。不管怎么样,它还是一个相当不错的产品。 Hibernate是一个现在很火热的O/R Mapping产品,目前已经出到2.0版,它功能一样强大,同样使用Java反射API进行对象的设置,但它的查询语言就是一套比较独特的体系,这一点有点类似TopLink,但Hibernate更具有亲和力,对关系的查询更方便,只不过比起Castor来,在方便性和规范性上还是稍逊一筹。就目前状况而言,Hibernate的用户量和技术支持要强一些。
3.2 面向对象的数据库查询
在对数据库进行面向对象研究的过程中,软件世界的开发人员和设计人员们发现:对数据库能够进行对象化的查询,才是对数据库进行彻底的面向对象化。这体现在我们使用一种全新的数据库查询语言,能够很简洁易懂地对数据库中的对象进行查询。一个典型的例子如下: 假设我们已经有前面提到的两个数据类:User和Group,它们之间有一对多的关系:User.belongTo和Group.users。在数据库中已经存在很多这两个类的实例,以及相互之间的关系。我们可以使用下面的对象式查询语言来查询符合条件的User对象: select * from User where User.belongTo.name=’GROUP1’ 或者 select userId,name from User where User.belongTo.name=’GROUP2’ 等等。从中我们可以看出,通过使用面向对象中的成员属性指定符“.”,可以让我们达到SQL中的连表的效果,实际上,第一个句查询的SQL等价版本是: select a.* from USER a, GROUP b where a.BELONG_TO = b.GROUP_ID and b.NAME = ‘GROUP1’
由此可见,对象式的查询语言,比起实现同样功能的SQL语言来说,简单了很多,意义也更明确,更符合使用者的思维习惯。在类图比较复杂、查询涉及的类又比较多的时候,这种新型的查询语言体现出绝对的优势。
3.2.1 ODMG,OQL,Java Binding
在面向对象式查询语言的研究过程中,开发人员们逐渐实现了相似的查询语言,然后互想取长补短,最终在ODMG组织(www.odmg.org)的统一下,形成了规范化的语言:ODMG OQL,这是一种完全面向对象的数据库查询语言,语法与前面提到的类似,不过考虑了更广泛的情况,语句更加简洁而严谨。 OQL并不是针对某种语言的,它可以被应用到很多种开发语言中,它不象SQL那样只是纯字符串式的查询语句,因为面向对象查询中还必须提供相关类的信息,所以OQL需要在编程语言中实现一些特定的API。 目前,ODMG的OQL已经被规范化地应用到SmallTalk、Java、C++这些面向对象的程序设计语言当中,在ODMG的规范中,这几个模块被称作SmallTalk Binding、Java Binding和C++ Binding。 不过,由于历史原因,ODMG并没有象想象中地那样得到广泛应用,现有的十几个面向对象数据库中,采用ODMG OQL规范的少之又少,目前也只有FastObjeccts、Ozone这些产品采纳了这个规范,而象Versant这样的大厂商还没有采取OQL来查询数据库,而是自己定义了自己的一套API,称作VQL(Versant Query Lanaguage)。 在JDO之前的O/R Mapping产品中,也有一些产品使用OQL(有时候是其子集),比如Castor、Apache的Jakarta小组开发的OJB等等。
3.2.2 第三方协议
软件世界是一个多姿多彩的世界,总有那么一些好事之士不断地冒出新奇的想法。还有一些开发面向对象数据库的组织制定了自己的一套对象式数据库查询语言,自己的规范。 不过这些规范相对来说,影响力小得多。比起ODMG来,可以说应用范围太小,更不用说与SQL这样广泛应用的标准进行比较了。
3.2.3 EJBQL
Sun为了使Java应用在企业级数据库应用中,不遗余力地推广J2EE,在2001年的时候,推出了EJB2.0规范,其中包含了富有特色的面向CMP方式的EntityBean的查询语言:EJBQL,功能类似于ODMG OQL,只不过只能在EJB发布时静态地存在于应用描述符中,不能在程序中动态地使用。这是EJBQL最大的弱点,也许EJB3.0规范会将其动态化,但到了那一天,世界多半已经不是现在的样子了。
3.2.4 JDO
JDO中有最近规定的一个对象式查询语言规范,称作JDOQL,比起OQL来,JDOQL将查询语言中的很多元素与Java语言紧密地结合在一起,有的人觉得麻烦,有些人觉得规范,评论各不相同。从笔者个人的角度来看,这样有利于没写过数据库应用、没用过SQL的新手很快地习惯JDOQL,但实际上,有多少人会在没写过SQL,没了解过关系数据库的情况下去用JDO写数据库应用呢?毕竟市场说明了一切。个人认为,JDO中对数据库对象的查询多少显得有些累赘,如果能更简化一点,那将更吸引使用传统SQL的开发人员。
4 JDO历程与主要产品
说起JDO,其来由还有一段特殊的背景。Java语言在JDK1.1达到比较实用的目的后,企业级数据库应用也正是软件开发市场中的重要组成部分,Sun看到这一点后,也希望通过Java这个强大的武器在数据库开发市场攻占市场份额。JDK1.2推出后,Sun同时推出了面向企业应用的EJB,对基于java的中间件服务器框架进行了规范化定义,这就是J2EE。不过在JDK1.2时,Java的速度还是不能与传统的C/C++和Delphi这样一些应用开发语言相比。为了防止业界对Java的激情因此而消退,Sun宣布将在JDK中加入强大的虚拟机技术HotSpot,其中包含更先进的垃圾收集算法和更优化的Java字节代码再编译技术(相当于JIT,Java即时编译技术)。HotSpot引起了Java关注者的极大兴趣,但Sun的HotSpot一拖再拖,最后包含在JDK1.3中出来时,性能也没有象预期的那样好,比起C++编译生成的代码来还是有一段距离。 这个时候,大家开始对Sun心存怀疑,而Sun深知这一点,于是将公众的注意力赶紧转移到EJB上,从EJB1.0到EJB1.1,再到EJB2.0,业界又开始关注J2EE中间件技术上来。很快,开发人同发现用EJB来编写数据库应用还是有很大的难度,虽然在分布式技术上EJB确实有很大的价值。在这个时候,Sun决定推出JDO技术作为轻量级的Java数据库访问规范,而这一点也受到很多传统O/R Mapping市场的欢迎。为了与传统O/R Mapping有所区别,Sun一开始就高姿态地将JDO定位成不只是面向关系数据库的Java规范,而是针对所有的存储技术,包括面向对象数据库和其它类型的存储体系(如文件),就象EJB EntityBean一样,虽然。就笔者的角度,这个做法使第一版的JDO抛弃了很多传统O/R Mapping提供的面向关系数据库的功能,可以算是一个失策。
4.1 规范提出、JSR
JDO最早是由Sun召集众多的O/R Mapping开发团队集中起来共同提出的,首先是通过会议确定了JDO需要包括的内容,然后正式提出一个Java规范请求(JSR-12),正式开始了JDO规范的制定。下面是主要的进展里程碑。 JSR #000012 approved in July 1999 1999-8组建的专家小组:包括Sun、Apple、BEA、IBM、Oracle、SAP、WebGain等 2000-5 完成公开评论草案 2000-6 在JavaOne上引入 2001-3 最终草案0.93 2001-5 最终草案0.96公布 2001-6 在JavaOne上启动 2001-11 最终草案0.98 2002-4 1.0版正式公布 2002-8 1.0.1修正版 2003-8 2.0规范启动 …
4.2 Oracle与JDO
作为JDO专家组的重要成员,同时作为最大的关系数据库厂商的Oracle地位显然非同一般。在JDO规范中,Oracle也可说是立下汗马功劳,很多API的形成,Oracle都提供了很重要的参考意见,最终的投票Oracle也是毫不犹豫。 可是,世间的事总是变化莫测的,就在JDO1.0快出台之时,Oracle收购了TopLink,这一点使Oracle的身份变得特殊而复杂。TopLink是一个商业产品,是以商业利益为目标的,而Oracle也是追求利益最大化的典型商家,这一点与JDO的开放精神背道而驰。因此,我们看到后期Oracle对JDO的不积极态度,甚至在前一阵的JavaOne大会上有人从Oracle的角度非正式地攻击JDO。
4.3 主要产品以及各自特点
在JDO规范制定的同时,出现了几个主要的JDO产品,有美国的基于对象数据库的FastObjects j1、法国的支持Versant对象数据库、文件数据库、主流RDBMS的LiDO、南非的JDOGenie、德国的JRelay等等,这些都是很不错的JDO产品。下面列举一下我对主要的几个产品的印象: LiDO(法国LibeLis公司) 我对JDO的认识主要是通过LiDO这个产品,它在2002年3月的一份图文并茂的教程中简要解说了JDO的使用和优点。这个教程可以在这里下载:http://www.objectweb.org/conference/JDO.pdf。LiDO的特色是大而全,支持文件型数据库、RDBMS、ODBMS,甚至是XML数据库。不过配置较麻烦。最新版本是2.0RC。 KodoJDO(美国SolarMetrics公司) Kodo是JDO的中流砥柱之一,在JDO1.0还未最后通过的时候,它就是一个比较成熟的产品了,其特点是注重性能和稳定性,目前最新版本是2.5.0,是客户最多的产品。 JDOGenie(南非HemSphere公司) 这是目前我最推荐的产品,最新版本是1.4.7,性能也不错,稳定性还有待验证,但它有一个最大的特点:集成性好,最易学,其公司的CTO David Tinker也是一个善解人意的年轻人,采纳了很多网友的意见对产品进行改进,主要是在配置上非常方便,有一个专门的图形界面工具,可以进行配置、数据库生成、对象查询等等很实用的功能。 JRelay(德国ObjectIndustries公司) 这也是一个出现得比较早的产品,也有一个GUI工具用于配置,曾几何时,这个工具还是相对很方便的,但一年多过去了,好象没什么进展,最新版本是2.0,我试过一段时间,后来就没有再跟进了。 FrontierSuite for JDO (美国ObjectFrontier) 这个产品与JRelay、Kodo一起,可算是早期的JDO三个主要产品,它支持正向开发和反向开发(Reverse Engineer)。它的特色是反向工程(从表结构生成数据类)比较方便,与UML的结合也很强,不过真正运行起来的时候,配置复杂。 TJDO(一群跨国界的有志之士) 这是一个在Sun提供的参考产品(Reference Implementation)的基础上加入一些扩展功能而形成的一个免费产品,目前最新版本是2.0beta3,不过进展也缓慢,这个版本已经出现好几个月了没有进一步的更新。
5 目前状况与未来展望
从2002年4月JDO1.0规范正式公布以来,各个产品层出不穷,从商业到免费的层次,都有不错的产品推出。象Kodo、Lido、JDOGenie等产品都已经比较成熟,可以考虑投入开发使用。在2002年8月,JDO又推出1.0.1修正版,修正了1.0版规范中的一些文字错误,以及轻微地改进了部分异常定义,不过改动都不大。从现在的情形来看,除了Kodo有一些大学的项目用到外,好象还没看到多少使用JDO作开发的应用。 JDO毕竟是一个新技术,从概念上到实际应用上对其掌握的用户还不多,而这些产品在配置、使用上的方便性易用性还有待大幅度改进,因此,真正用JDO来开发项目的用户还廖廖无几,至少我还不知道有哪些项目使用了JDO。我自己也尝试使用JDO来开发项目,但由于一些JDO1.0版本中还不够完善的一些硬伤(比如不支持关系数据库统计功能),使我对JDO仍处于观望阶段。 在八月中旬进行的JDO2.0规划会议中,来自各国的各个JDO产品厂商、JDO技术咨询公司、JDO研究机构的代表汇聚一堂,将各自收集到的用户对JDO2.0的需求总结起来,提出一个个的新的议题,并且确定了每个议题的JDO规范撰写负责人,比如高级fetchGroup特性由目前实现得最好的JDOGenie的CTO David Tinker负责,关于managed-relationship特性由Kodo的产品总监负责,用户要求最多的JDO对象与PersistenceManager的脱钩/重挂钩特性由Sun的Craig Russell亲自操刀,等等。 最具有吸引力的JDO2.0议题,笔者个人认为是专门为关系数据库设立的子规范JDO/R,这也是我一直以来最关心的,这将使目前JDBC的开发将可以被JDO完全取代,并且保证开发过程保持面向对象的特色。还有一些将一个类映射到多个表之类的特性也在规范化的列表上,这将有利于DBA在不影响应用开发的前提下根据需要更改数据表结构,实现更好的性能。类似的新特性还有很多,粗略地看,这些都规范化起来后,真不知道各个厂商还能做什么样的扩展特性,也许以后厂商之间拼的只能是技术支持服务和产品性能了,当然,最后还有价格的竞争。 说了这么多,我想大家关心的还是JDO2.0到底什么时候能出来,我们什么时候可以用上它,什么时候有中文版产品,价格到底如何。这些问题目前笔者还无法一一回答,只能根据笔者所掌握的信息初步解释一下。据前几天的JDO2.0启动大会上David Jordan的预期,JDO2.0正式版将在18个月后正式完成。那正式完成后厂商什么时候才能提供符合规范的产品呢?这个问题不用担心,因为规范在制定的过程中会不断地公布公众预览版(Public Review),这样,厂商可以先实现其中的功能,等规范正式完成后,也不会有太大的变化,厂商也不会需要太多时间来跟进最终规范。所以,我估计一年之后,我们就可以在JDO2.0上进行开发了。至于价格如何,1.0规范的产品初步印象是每个开发人员需要一个License,一个License大概2000美元。如果JDO2.0产品的价格还保持这么贵的话(至少对中国用户来说),我们也还有很多免费(如JPOX,TJDO)或半免费(如JCredo)产品可以选择。最后一个关于中文版的问题,有待于厂商对中国市场的考察,或者看看是否有国内的JDO产品了。不过,在JDO2.0规范制定的同时,我们可以先集众人之力将其普及,使广大的使用Java语言进行数据库开发的开发人员都来认识JDO,了解JDO,甚至将其用到项目开发之中。 也许,JDO的目标已经吸引了Java世界以外的人,微软发现了这一点,也立即计划在.NET体系中加入一个仿照JDO的中间件,具体是采用ObjectStore的产品,ObjectStore是一个同时做JDO和.NET-DO(姑且使用这个名称)的公司。
在这里,笔者可以大胆地预测,在未来的一两年内,JDO将在Java世界大放光彩!
5.1 一点花絮
在2003年6月举行的JavaOne大会上,JDO备受瞩目,很多开发者或开发组织对其产生了极大的兴趣,在各大网站媒体上也频频曝光,大多对其评价不错,当然,也有一些负面的评价。 不过,网站上的报道也不可尽信,比如服务器领域的权威网站TheServerSide.com上介绍JavaOne大会第二天关于JDO的一次会议的报道就有误导之嫌,从报道的内容来看,好象会议用来答疑与交流的的最后五分钟全被一个好事者占据,这个人拼命鼓吹Oracle的TopLink解决方案和一些易用性的改进,从而攻击JDO的市场前景。后来,我就这一信息与参加会议的JDO专家组的David Jordan交流时,他纠正了我的错误理解,实际情形是:那个好事者是一个积极的JDO拥护者,他花了超过五分钟时间向大家揭露Oracle的TopLink改进实际上也是抄袭JDO的概念而进行的一些API改动!不过有一点是相同的,这个好事者占据了大家的提问时间,使这次会议在意犹未尽中结束。
本文的版权属于笔者本人,但欢迎转载,前提是注明出处和原作者。另外,欢迎在我的专栏中查看我的另几篇文章,并提出宝贵意见!
|
|
http://www.javazy.com/contentex/2007413143952.shtml
|