分享

JDBC进化史---从JDBC1.0到JDBC4.2

 明神月 2017-08-11
该文转自 【转自 http://blog.csdn.net/u011179993 】

JDBC是一种可用于执行SQL语句的JavaAPI(ApplicationProgrammingInterface应用程序设计接口)。它由一些Java语言编写的类和界面组成。JDBC为数据库应用开发人员、数据库前台工具开发人员提供了一种标准的应用程序设计接口,使开发人员可以用纯Java语言编写完整的数据库应用程序。

本文简单介绍了JDBC1.0---JDBC4.2的发展,简单介绍了每个版本的新特性。


一、ODBC到JDBC的发展历程

说到JDBC,很容易让人联想到另一个十分熟悉的字眼“ODBC”。它们之间有没有联系呢?如果有,那么它们之间又是怎样的关系呢?

ODBC是OpenDatabaseConnectivity的英文简写。它是一种用来在相关或不相关的数据库管理系统(DBMS)中存取数据的,用C语言实现的,标准应用程序数据接口。通过ODBCAPI,应用程序可以存取保存在多种不同数据库管理系统(DBMS)中的数据,而不论每个DBMS使用了何种数据存储格式和编程接口。

ODBC的结构模型

ODBC的结构包括四个主要部分:应用程序接口、驱动器管理器、数据库驱动器和数据源。

应用程序接口:屏蔽不同的ODBC数据库驱动器之间函数调用的差别,为用户提供统一的SQL编程接口。
驱动器管理器:为应用程序装载数据库驱动器。
数据库驱动器:实现ODBC的函数调用,提供对特定数据源的SQL请求。如果需要,数据库驱动器将修改应用程序的请求,使得请求符合相关的DBMS所支持的文法。
数据源:由用户想要存取的数据以及与它相关的操作系统、DBMS和用于访问DBMS的网络平台组成。

虽然ODBC驱动器管理器的主要目的是加载数据库驱动器,以便ODBC函数调用,但是数据库驱动器本身也执行ODBC函数调用,并与数据库相互配合。因此当应用系统发出调用与数据源进行连接时,数据库驱动器能管理通信协议。当建立起与数据源的连接时,数据库驱动器便能处理应用系统向DBMS发出的请求,对分析或发自数据源的设计进行必要的翻译,并将结果返回给应用系统。

JDBC的诞生

自从Java语言于1995年5月正式公布以来,Java风靡全球。出现大量的用java语言编写的程序,其中也包括数据库应用程序。由于没有一个Java语言的API,编程人员不得不在Java程序中加入C语言的ODBC函数调用。这就使很多Java的优秀特性无法充分发挥,比如平台无关性、面向对象特性等。随着越来越多的编程人员对Java语言的日益喜爱,越来越多的公司在Java程序开发上投入的精力日益增加,对java语言接口的访问数据库的API的要求越来越强烈。也由于ODBC的有其不足之处,比如它并不容易使用,没有面向对象的特性等等,SUN公司决定开发一Java语言为接口的数据库应用程序开发接口。在JDK1.x版本中,JDBC只是一个可选部件,到了JDK1.1公布时,SQL类包(也就是JDBCAPI)就成为Java语言的标准部件。


二.JDBC 1.0

JDBC 1.0 随JDK1.1一起发布,JDBC操作相关的接口和类位于java.sql包中。包含了DriverManager类,Driver接口,Connection接口,Statement接口,ResultSet接口,SQLException 类等。


三、JDBC 2.0

DBC 2.0 API被划分为两部分:核心API扩展API

核心API(java.sql包)

概括的来说,JDBC核心API的新特性在两个方面做了工作。一个是支持一些新的功能,另一个就是支持新的SQL的数据类型。
1、 在支持新功能方面:包括结果集可以向后滚动,批量的更新数据。另外,还提供了UNICODE字符集的字符流操作。
2、 在支持SQL的数据类型方面:新增加的BLOB, CLOB,和数组接口能够是应用程序操作大块的数据类型,

扩展API(javax.sql包)

1  DataSource接口:和Java名字目录服务(JNDI)一起工作的数据源接口。

       JDBC1.0是原来是用DriverManager类来产生一个对数据源的连接。JDBC2.0用一种替代的方法,使用DataSource的实现,代码变的更小巧精致,也更容易控制。一个DataSource对象代表了一个真正的数据源。当一个DataSource对象注册到名字服务中,应用程序就可以通过名字服务获得DataSource对象,并用它来产生一个与DataSource代表的数据源之间的连接。
  关于数据源的信息和如何来定位数据源,例如数据库服务器的名字,在哪台机器上,端口号等等,都包含在DataSource对象的属性里面去了。这样,对应用程序的设计来说是更方便了,因为并不需要硬性的把驱动的名字写死到程序里面去。
  由系统管理员或者有相应权限的人来配置DataSource对象。配置DataSource,包括设定DataSource的属性,然后将它注册到JNDI名字服务中去。在注册DataSource对象的的过程中,系统管理员需要把DataSource对象和一个逻辑名字关联起来。名字可以是任意的,通常取成能代表数据源并且容易记住的名字。在下面的例子中,逻辑名字的全名是:jdbc/MySqlDB。
  一旦配置好了数据源对象,应用程序设计者就可以用它来产生一个与数据源的连接。下面的代码片段示例了如何用JNDI上下文获得一个一个数据源对象,然后如何用数据源对象产生一个与数据源的连接:
   

  1. //======代码3.1========  
  2. Context ctx = new InitialContext();   
  3. DataSource ds = (DataSource)ctx.lookup("jdbc/InventoryDB");  
  4. Connection con = ds.getConnection("myPassword""myUserName");  

  在一个基本的DataSource实现中,DataSource.getConnection方法返回的Connection对象和用DriverManager.getConnection方法返回的Connection对象是一样的。因为DataSource提供的方便性,我们推荐使用DataSource对象来得到一个Connection对象


2、 Connection pooling(连接池):

可以重复使用连接,而不是对每个请求都使用一个新的连接。如果DataSource对象实现与一个支持连接池的中间层的服务器一起工作,DataSource对象就会自动的返回连接池中的连接,这个连接也是可以重复利用的。


3、 Distrubute Transaction(分布式的事务):在一个事务中涉及到了多个数据库服务器。

获得一个用来支持分布式事务的连接与获得连接池中的连接是很相似的。同样,不同之处在于DataSource的实现上的不同,而不是在应用程序中获得连接的方式上有什么不同。


4、 Rowsets:

RowSet是在驱动的上层实现的,可以由其它的任何人来实现他们

任何类型的rowset都实现了RowSet接口,RowSet接口扩展了ResultSet接口。这样RowSet对象就有了ResultSet对象所有的功能。

我们更感兴趣的是RowSet接口提供的新的功能。作为一个JavaBean组件,RowSet对象可以增加或者删除一个listener(监听者),可以get或者set其属性值,这些属性中,有一个是字符串,表示一个对数据库Query请求,RowSet接口定义了设定参数的方法,也提供了执行这个请求的方法。这意味着RowSet对象能够执行查询请求,可以根据它产生的结果集进行计算。同样,RowSet也可以根据任何表格数据源进行计算,所以,它不局限于关系数据库。

总结

JDBC2.0标准扩展API通过见DataSource注册到JNDI名字服务上,将JDBC技术扩展为一个全新的概念。使应用程序的代码更加精巧,易于控制。新的API支持了连接池,支持分布式的事务。最后,还使java应用程序可以在网络上传播结果集,是不可以滚动的ResultSet变成了可以滚动的RowSet。



四、JDBC 3.0

【参考http://www.ibm.com/developerworks/cn/java/j-jdbcnew/】

JDBC3.0随JDK1.4一起发布,下面看看它的特性吧!

元数据 API

DatabaseMetaData 接口可以检索 SQL 类型的层次结构,一种新的 ParameterMetaData 接口可以描述 PreparedStatement 对象中参数的类型和属性。

CallableStatements 中已命名的参数

JDBC 3.0 之前,设置一个存储过程中的一个参数要指定它的索引值。现在您可以用名称来指定参数。

数据类型的改变

JDBC 所支持的数据类型作了几个改变,其中之一是增加了两种新的数据类型。
增加的两种新的数据类型是 java.sql.Types.DATALINK 和 java.sql.Types.BOOLEAN 。DATALINK 提供对外部资源的访问或 URL,而 BOOLEAN 类型在逻辑上和 BIT 类型是等同的,只是增加了在语义上的含义。DATALINK 列值是通过使用新的 getURL() 方法从 ResultSet 的一个实例中检索到的,而 BOOLEAN 类型是通过使用 getBoolean() 来检索的。

检索自动产生的关键字

为了解决对获取自动产生的或自动增加的关键字的值的需求,JDBC 3.0 API 现在将获取这种值变得很轻松。要确定任何所产生的关键字的值,只要简单地在语句的 execute() 方法中指定一个可选的标记,表示您有兴趣获取产生的值。您感兴趣的程度可以是 Statement.RETURN_GENERATED_KEYS ,也可以是 Statement.NO_GENERATED_KEYS 。在执行这条语句后,所产生的关键字的值就会通过从 Statement 的实例方法 getGeneratedKeys() 来检索 ResultSet 而获得。 ResultSet 包含了每个所产生的关键字的列。如下:

  1. Statement stmt = conn.createStatement();  
  2.   
  3. stmt.executeUpdate("INSERT INTO authors " +  
  4.            '(first_name, last_name) " +  
  5.            "VALUES ('George', 'Orwell')",  
  6.            Statement.RETURN_GENERATED_KEYS);  
  7. ResultSet rs = stmt.getGeneratedKeys();  
  8. if ( rs.next() ) {  
  9.     // Retrieve the auto generated key(s).  
  10.     int key = rs.getInt();  
  11. }  

连接器关系

J2EE 连结器体系结构指定了一组协议,允许企业的信息系统以一种可插入的方式连接到应用服务器上。这种体系结构定义了负责与外部系统连接的资源适配器。连接器服务提供者接口(The Connectors Service Provider Interface,SPI)恰好和 JDBC 接口提供的服务紧密配合。
JDBC API 实现了连结器体系结构定义的三个协议中的两个。第一个是将应用程序组件与后端系统相连接的连接管理,它是由 DataSource 和 ConnectionPoolDataSource 接口来实现的。第二个是支持对资源的事务性访问的事务管理,它是由 XADataSource 来处理的。第三个是支持后端系统的安全访问的安全性管理,在这点上,JDBC 规范并没有任何对应点。尽管有最后那个不足,JDBC 接口仍能映射到连接器 SPI 上。如果一个驱动程序厂商将其 JDBC 驱动程序映射到连接器系统协议上,它就可以将其驱动程序部署为资源适配器,并立刻享受可插性、封装和在应用服务器中部署的好处。这样,一个标准的 API 就可以在不同种类的的企业信息系统中,供企业开发人员使用。

ResultSet 可保持性

一个可保持的游标(或结果),就是说该游标在包含它的事务被提交后,也不会自动地关闭。JDBC 3.0 增加了对指定游标可保持性的支持。要制定您 ResultSet 的可保持性,您必须在使用 createStatement() 、 prepareStatement() 或 prepareCall() 方法准备编写一条语句时就这么做。

总的来说,在事务提交之后关闭游标操作会带来更好的性能。除非您在事务结束后还需要该游标,否则您最好在执行提交操作后将其关闭。因为规范没有规定 ResultSet 的缺省的可保持性,所以具体行为还将取决于执行情况。然而,我希望在可以使用 JDBC 3.0 驱动程序时,大多数执行在事务结束后仍旧会关闭游标。

返回多重结果

JDBC 2 规范的一个局限是,在任意时刻,返回多重结果的语句只能打开一个 ResultSet 。作为 JDBC 3.0 规范中改变的一个部分,规范将允许 Statement 接口支持多重打开的 ResultSets。然而,重要的是 execute() 方法仍然会关闭任何以前 execute() 调用中打开的 ResultSet 。所以,要支持多重打开的结果, Statement 接口就要加上一个重载的 getMoreResults() 方法。新式的方法会做一个整数标记,在 getResultSet() 方法被调用时指定前一次打开的 ResultSet 的行为。

连接池

JDBC 3.0 定义了几个标准的连接池属性。开发人员并不需要直接地用 API 去修改这些属性,而是通过应用服务器或数据存储设备来实现。由于开发人员只会间接地被连接池属性的标准化所影响,所以有利之处并不明显。然而,通过减少厂商特定设置的属性的数量并用标准化的属性来代替它们,开发人员能更容易地在不同厂商的 JDBC 驱动程序之间进行交换。另外,这些属性还允许管理员很好地优化连接池,从而使应用程序的性能特点发挥到极致。

预备语句池

除了改进对连接池的支持以外,现在也能缓冲预备语句了。预备语句允许您用一条常用的 SQL 语句然后预编译它,从而在这条语句被多次执行的情况下大幅度地提升性能。在另一个方面,建立一个 PreparedStatement 对象会带来一定量的系统开销。所以,在理想情况下,这条语句的生命周期应该足够长,以补偿它所带来的系统开销。追求性能的开发人员有时候为了延长 PreparedStatement 对象的生命周期会不惜扭曲他们的对象模型。JDBC 3.0 让开发人员不再为此担心,因为数据源层现在负责为预备语句进行缓存。语句和普通 JDBC 2 的代码没什么两样。这是因为语句的缓冲是完全在内部实现的。这就意味着,在 JDBC 3.0 下,您现存的代码可以自动利用语句池。



五.JDBC 4.0 (  JDK 1.6 )

【更多:https://www.ibm.com/developerworks/cn/java/j-lo-jse65/】

Java DB

JDK 6安装目录下,除了传统的 bin、jre 等目录,又新增了一个名为 db 的目录。这便是 Java 6 的新成员:它是一个纯 Java 实现、开源的数据库管理系统(DBMS),源于 Apache 软件基金会(ASF)名下的项目 --- Derby,它只有 2MB 大小。

自动加载驱动

从 Java 6 开始,应用程序不再需要显式地使用Class.forName("驱动名称")加载驱动程序了,DriverManager 开始能够自动地承担这项任务(在DriverManager 载入时会自动加载驱动)。

RowId

熟悉 DB2、Oracle 等大型 DBMS 的人一定不会对 ROWID 这个概念陌生:它是数据表中一个“隐藏”的列,是每一行独一无二的标识,表明这一行的物理或者逻辑位置。由于 ROWID 类型的广泛使用,Java SE 6 中新增了 java.sql.RowId 的数据类型,允许 JDBC 程序能够访问 SQL 中的 ROWID 类型。诚然,不是所有的 DBMS 都支持 ROWID 类型。即使支持,不同的 ROWID 也会有不同的生命周期。因此使用 DatabaseMetaData.getRowIdLifetime 来判断类型的生命周期不失为一项良好的实践经验。

SQLXML

SQL:2003 标准引入了 SQL/XML,作为 SQL 标准的扩展。SQL/XML 定义了 SQL 语言怎样和 XML 交互:如何创建 XML 数据;如何在 SQL 语句中嵌入 XQuery 表达式等等。作为 JDBC 4.0 的一部分,Java 6 增加了 java.sql.SQLXML 的类型。JDBC 应用程序可以利用该类型初始化、读取、存储 XML 数据。java.sql.Connection.createSQLXML 方法就可以创建一个空白的 SQLXML 对象。当获得这个对象之后,便可以利用 setString、setBinaryStream、setCharacterStream 或者 setResult 等方法来初始化所表示的 XML 数据。

SQLExcpetion 的增强

在 Java SE 6 之前,有关 JDBC 的异常类型不超过 10 个。这似乎已经不足以描述日渐复杂的数据库异常情况。因此,Java SE 6 的设计人员对以 java.sql.SQLException 为根的异常体系作了大幅度的改进。
Java 6 中新增的异常类被分为 3 种:SQLReoverableException、SQLNonTransientException、SQLTransientException。在 SQLNonTransientException 和 SQLTransientException 之下还有若干子类,详细地区分了 JDBC 程序中可能出现的各种错误情况。大多数子类都会有对应的标准 SQLState 值,很好地将 SQL 标准和 Java 6 类库结合在一起。

六.JDBC 4.1 ( JDK 1.7 )

Connection,ResultSet 和 Statement 都实现了Closeable 接口

所有在 try-with-resources 语句中调用,就可以自动关闭相关资源
  1. try (Statement stmt = con.createStatement()){    
  2.         …    
  3. }    

RowSet 1.1:

引入RowSetFactory接口和RowSetProvider类,可以创建JDBC driver支持的各种 row sets
  1. RowSetFactory myRowSetFactory = null;    
  2. JdbcRowSet jdbcRs = null;    
  3. ResultSet rs = null;    
  4. Statement stmt = null;    
  5.     
  6. try {    
  7.     
  8.   myRowSetFactory = RowSetProvider.newFactory();//用缺省的RowSetFactory 实现    
  9.   jdbcRs = myRowSetFactory.createJdbcRowSet();    
  10.       
  11.   //创建一个 JdbcRowSet 对象,配置数据库连接属性    
  12.   jdbcRs.setUrl("jdbc:myDriver:myAttribute");    
  13.   jdbcRs.setUsername(username);    
  14.   jdbcRs.setPassword(password);    
  15.     
  16.   jdbcRs.setCommand("select ID from TEST");    
  17.   jdbcRs.execute();    
  18. }    

RowSetFactory 接口包括了创建不同类型的RowSet的方法
·createCachedRowSet
·createFilteredRowSet
·createJdbcRowSet
·createJoinRowSet
·createWebRowSet

七.JDBC 4.2(JDK1.8)

【参考 jsr221 chapter 3: Summary of New Fetures】

增加了对REF Cursor的支持

修改返回值大小范围(update count)

增加了java.sql.DriverAction接口

增加了java.sql.SQLType接口

增加了java.sql.JDBCtype枚举

对java.time包时间类型的支持

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多