您现在的位置是:网站首页> 编程资料编程资料

JDBC板块精华整理20051226_JSP编程_

2023-05-25 311人已围观

简介 JDBC板块精华整理20051226_JSP编程_

重要提示:本文部分内容是斑竹从网上搜集整理而来,如果您认为该文档的内容侵犯了您的权益,请与整理者(excelarthur@yahoo.com.cn)联系,与dev2dev网站无关。

JDBC3.0的特性

1、JDBC3.0规范中数据库连接池框架
  JDBC3.0规范中通过提供了一个支持数据库连接池的框架,这个框架仅仅规定了如何支持连接池的实现,而连接池的具体实现JDBC 3.0规范并没有做相关的规定。通过这个框架可以让不同角色的开发人员共同实现数据库连接池。

  通过JDBC3.0规范可以知道具体数据库连接池的实现可以分为JDBC Driver级和Application Server级。在JDBC Driver级的实现中任何相关的工作均由特定数据库厂商的JDBC Drvier的开发人员来具体实现,即JDBC Driver既需要提供对数据库连接池的支持同时也必须对数据库连接池进行具体实现。而在Application Server级中数据库连接池的实现中的特定数据库厂商的JDBC Driver开发人员和Application Server开发人员来共同实现数据库连接池的实现(但是现在大多数Application Server厂商实现的连接池的机制和规范中提到有差异),其中的特定数据库厂商的JDBC Driver提供数据库连接池的支持而特定的Application Server厂商提供数据库连接池的具体实现。

  JDBC3.0规范规定了如下的类和接口来支持数据库连接池的实现。

javax.sql.ConnectionEvent javax.sql.ConnectionPoolDataSource javax.sql.PooledConnection javax.sql.ConnectionEventListener 

  其中除javax.sql.ConnectionEvent是类,其它的均为接口。

  

JDBC3.0连接池框架的关系图

  通过此图可以大概的了解相关接口在一个典型的三层环境中应用程序的位置。

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

…… Statement stmt = conn.createStatement(); // Obtain the generated key that results from the query. stmt.executeUpdate("INSERT INTO authors " + "(first_name, last_name) " + "VALUES (‘Ghq’, ‘Wxl’)", Statement.RETURN_GENERATED_KEYS); ResultSet rs = stmt.getGeneratedKeys(); if ( rs.next() ) { // Retrieve the auto generated key(s). int key = rs.getInt(); } …… 

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

  CLOSE_ALL_RESULTS:当调用 getMoreResults() 时,所有以前打开的 ResultSet 对象都将被关闭。

  CLOSE_CURRENT_RESULT:当调用 getMoreResults() 时,当前的 ResultSet 对象将被关闭。

  KEEP_CURRENT_RESULT:当调用 getMoreResults() 时,当前的 ResultSet 对象将不会被关闭。

  下面展示的是一个处理多重打开结果的示例。

…… String procCall; // Set the value of procCall to call a stored procedure. // … CallableStatement cstmt = connection.prepareCall(procCall); int retval = cstmt.execute(); if (retval == false) { // The statement returned an update count, so handle it. // … } else { // ResultSet ResultSet rs1 = cstmt.getResultSet(); // … retval = cstmt.getMoreResults(Statement.KEEP_CURRENT_RESULT); if (retval == true) { ResultSet rs2 = cstmt.getResultSet(); // Both ResultSets are open and ready for use. rs2.next(); rs1.next(); // … } } …… 

4、在事务中使用 Savepoint
  也许在 JDBC 3.0 中最令人兴奋的附加特点就是 Savepoint 了。JDBC 2 中的事务支持让开发人员可以控制对数据的并发访问,从而保证持续数据总是保持一致的状态。可惜的是,有时候需要的是对事务多一点的控制,而不是在当前的事务中简单地对每一个改变进行回滚。在JDBC 3.0 下,可以通过 Savepoint 获得这种控制。Savepoint 接口允许您将事务分割为各个逻辑断点,以控制有多少事务需要回滚。下图将说明如何在事务中运用 Savepoint。

  

Savepoint 的直观表示
  你或许不是经常需要使用 Savepoint。然而,在一种普遍的情况下 Savepoint 会发挥作用,那就是您需要作一系列的改变,但是在知道所有的结果之前不能确定应该保留这些改变的哪一部分。下面的代码示例说明了如何使用 Savepoint 接口。

...... conn.setAutoCommit(false); // Set a conservative transaction isolation level. conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); Statement stmt = conn.createStatement(); int rows = stmt.executeUpdate( "INSERT INTO authors " + " (first_name, last_name) VALUES " + " ('Ghq', 'Wxl')"); // Set a named savepoint. Savepoint svpt = conn.setSavepoint("NewAuthor"); // … rows = stmt.executeUpdate( "UPDATE authors set type = 'fiction' " + "WHERE last_name = 'Wxl'"); // … conn.rollback(svpt); // … // The author has been added, but not updated. conn.commit(); ...... 

5、其他的特性
  1)元数据 API
  元数据 API 已经得到更新,DatabaseMetaData 接口现在可以检索 SQL 类型的层次结构,一种新的 ParameterMetaData 接口可以描述 PreparedStatement 对象中参数的类型和属性。

  2)CallableStatements 中已命名的参数
  在 JDBC 3.0 之前,设置一个存储过程中的一个参数要指定它的索引值,而不是它的名称。 CallableStatement 接口已经被更新了,现在您可以用名称来指定参数。

  3)数据类型的改变
  JDBC 所支持的数据类型作了几个改变,其中之一是增加了两种新的数据类型。

  为了便于修改 CLOB(Character Large OBject,字符型巨对象)、BLOB(Binary Large OBject,二进制巨对象)和 REF(SQL 结构)类型的值,同名的数据类型接口都被更新了。接下来的是,因为我们现在能够更新这些数据类型的值,所以 ResultSet 接口也被修改了,以支持对这些数据类型的列的更新,也包括对 ARRAY 类型的更新。增加的两种新的数据类型是 java.sql.Types.DATALINK 和 java.sql.Types.BOOLEAN。新增的数据类型指的是同名的 SQL 类型。DATALINK 提供对外部资源的访问或 URL,而 BOOLEAN 类型在逻辑上和 BIT 类型是等同的,只是增加了在语义上的含义。DATALINK 列值是通过使用新的 getURL() 方法从 ResultSet 的一个实例中检索到的,而 BOOLEAN 类型是通过使用 getBoolean() 来检索的。

二进制大对象Blob
  Blob对象是SQL Blob的Java语言映射。SQL Blob是一个内置类型,它可以将一个二进制大对象保存在数据库中。接口ResultSet、CallableStatement和PreparedStatement中的方法允许程序员使用与访问SQL 92内置类型同样的方式来访问SQL 99类型BLOB。

  在标准实现中,JDBC驱动程序在后台使用SQL类型LOCATOR(BLOB)来实现Blob接口。LOCATOR(BLOB)指向保存在数据库服务器上的SQL BLOB值,而且这些操作作用在这个LOCATOR上与作用在BLOB值本身有同样的结果。这意味着用户可以在一个Blob实例上执行操作而不必将这个BLOB数据物化到用户上,这将显著的提高性能。因为驱动程序在后台使用LOCATOR(BLOB),所以它的使用对程序员是完全透明的。

  Blob实例的标准行为一直保持有效,直到这个事务(创建一个Blob的事务)执行了提交或者回滚操作。

  1. 创建Blob对象
      下面的代码说明了如何创建一个Blob对象,其中stmt是一个Statement对象:
    Statement stmt = con..createStatement(ResultSet.TYPE_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet rs = stmt.excuteQuery(“SELECT DATA FROM TABLE 1”); If (rs.next()){ rs.first(); Blob blob=rs.getBlob(“DATA”); } 变量blob包含一个指向BLOB值的逻辑指针,该BLOB值保存在结果集rs的第一行的DATA列中。即使变量blob实际上并不包含BLOB值中的数值,应用程序在blob上执行操作仍然像在实际的数据上执行一样。即应用程序在blob上所作的任何操作都会对表中的BLOB值起作用。
  2. 物化BLOB数据
      开发人员可以在Blob对象上调用JDBC API中的方法,就像这些方法直接
      在该对象所指向的SQL BLOB上执行操作一样。然而,如果想在BLOB数据上执行操作,就必须首先将BLOB数据物化到客户。Blob接口提供了两个方法来物化BLOB数据:getBinaryStream,这个方法将BLOB数据物化为一个输入流;getBytes,这个方法将BLOB值得一部分或者全部物化为一个字节数组。下面的代码说明了如何将Blob所指向的BLOB值得全部物化为一个输入流:
     java.io.InputStream in = blob.getBinaryStream(); byte b; while((b = in.read()) >-1){ System.out.println(b); } 
    接下来的代码同样物化了blob所指向的BLOB值得所有数据,但是它产生的是字节数组而不是输入流。
     long len = blob.length(); byte [] data = blob.getBytes(1,len); for(int i=0;i  变量data复制了blob所指向的BLOB值的所有字节。这是因为传递给方法getBytes的参数值说明了整个BLOB值:第一个参数表示从第一个字节开始返回字节,第二个参数说明它返回的字节长度是BLOB值的长度。
      需要说明的是,因为SQL和Java语言之间的不同,一个BLOB值得第一个字节在位置1,而Java数组的第一个元素的索引是0。
  3. 存储Blob值
      若要在数据库中存储Blob值,应用程序可以把它作为一个参数传递给
      PreparedStatement的方法setBlob。下面的代码就实现了这个功能:
    PreparedStatement的方法setBlob。下面的代码就实现了这个功能: Blob stats = rs.getBlob(“STATS”); PreparedStatement pstmt= con.preparedStatement( “UPDATE SIGHTINGS SET MEAS= ? WHERE AREA = ‘BEIJING’ ”); pstmt.setBlob(1,stats); pstmt.excuteUpdate(); 
  4. 发现Blob对象中的模式
      如果一个Blob对象包含一个给定的字节集合,应用程序可以使用方法
      position的两个方法来找到它。其中一个方法搜索一个给定的字节数组,而另一个在一个Blob对象中搜索一个给定的Blob对象。如果发现一个匹配的结果,则返回该模式字节的起始位置。
  5. 修改Blob对象的方法
      JDBC 3.0 API中新增的方法setBytes和setBinaryStream允许应用程序对
      Blob对象进行修改。
      方法setBytes有两个方法来向Blob对象添加数据。其中一个方法增加给定的字节数组的全部内容,而另一个方法增加给定字节数组的特定部分。两个方法都使用一个参数说明向Blob对象插入数据的起始位置。例如,下面的代码段在一个Blob对象blob1的第一个字节处写入整个字节数组bytes。在这种情况下,bytes包含了Blob对象blob的所有字节,因此执行的结果是blob2被写入了blob1的起始处。需要注意的是如果blob2的长度是1024字节,那么blob2的1024各字节将覆盖blob1的开头的1024各字节。
    byte [] bytes = blob2.getBytes(1,blob2.length()); blob.setBytes(1,bytes,0,512); 
      下面的代码段说明如何仅仅向Blob对象加入一个字节数组的特定部分。在这种情况下,方法setBytes接受两个附加的参数来说明需要增加字节数组的哪一个部分。其中一个参数指明了这个字节数组的起始偏移量,另一个参数说明这个字节数组包含多少个连续的字节。
    byte [] bytes={……}; blob.setBytes(1,bytes,0,512); 
      除了可以向Blob对象增加字节之外,Blob接口还提供了删除字节的方法。方法truncate接受一个字节数目作为一个参数并且根据这个数目来缩短Blob对象。
  6. 更新
      为了发现DBMS是如何更新BLOB值的,应用程序可以调用DatabaseMetaData的方法locatorsUpdateCopy。如果这个方法返回true,则应用程序必须自己更新数据库中的BLOB值。下面的代码显示了这个过程:首先从rs取回Blob对象,然后把它的值改为字节数据val的值。如果方法locatorsUpdateCopy返回true,那么它随后执行一个PreparedStatement对象来更新数据库中的值。如果方法locatorsUpdateCopy返回false,代码什么也不用做,因为数据库中的值已经被更新过了。
    byte [] val ={0,1,2,3,4}; Blob data =rs.getBlob(“DATA”); int numWritten = data.setBytes(1,val); if (dbmd.locatorUpdateCopy() == true){ PreparedStatement pstmt= con . preparedStatement( “UPDATE statistics SET DATA = ? WHERE REGION = ‘BEIJING’ “); pstmt.setBlob(“DATA”,data); pstmt.executeUpdate(); } 

字符大对象Clob

  1. 创建Blob对象
      Clob clob = rs.getClob(1);
      变量clob现在可以被用于在CLOB值上执行操作,而假设这CLOB值保存在结果集rs的第一列中。

     

  2. 物化Clob数据
      和物化Blob的方式一样。不过Clob接口提供了三种方法达到将CLOB作为一个Java对象的形式保存在客户的内存中。
    使用getAsiiStream把CLOB值物化为一个包含Ascii字节的字符流。 ① 使用getAsiiStream把CLOB值物化为一个包含Ascii字节的字符流。 Clob notes = rs.getClob(“NOTES”); java.io.InputStream in = notes.getAsciiStream(); byte b = in.read(); ② 使用getCharacterStream把CLOB值物化为一个Unicode字符流。 Clob notes = rs.getClob(“NOTES”); java.io.Reader reader = notes.getCharacterStream(); int c = reader.read(); // ③ 使用getSubString将CLOB值的全部或者部分化为一个String对象。 Clob notes = rs.getClob(4); String substring= notes.getSubString(10,5); 或者 long len =notes.length(); String substring = notes.getSubString(1,(int)len);
  3. 存储、更新Clob对象
      和存储、更新Blob对象类似。

元数据接口使用详解
  三个元数据接口DatabaseMetaData、ResultSetMetaData和ParameterMetaData接口是三个常用的元数据接口。DatabaseMetaData提供与数据库或者DBMS相关的信息;ResultSetMetaData对象提供与特定ResultSet实例中与列相关的信息;ParameterMetaData对象提供与PreparedStatement对象的参数有关的信息。本文讨论的内容并不仅限于JDBC的某个版本,而是基于1.0—3.0的规范进行学习。

  • ResultSetMetaData对象
      当在JDBC应用程序中发送select语句时,该操作会返回一个ResultSet对象,这个ResultSet对象包含满足条件的数据。通过创建ResultMetaData对象和调用该对象的方法,可以获取与这个ResultSet对象中的列有关的信息。下面的代码段将创建ResultSet对象rs,然后使用rs来创建ResultSetMetaData对象,所创建的ResultSetMetaData对象包含与rs中的列有关的信息。
     Statement stmt= con . createStatement(); ResultSet rs = stmt.executeQuery(“select * from sales”); ResultSetMetaData rsmd = rs.getMetaData(); 
      现在可以使用rsmd调用ResultSetMetaData的方法来访问与rs中的列有关的信息。除了方法getColumnCount给出结果集中总的列数外,所有的Result

-六神源码网