﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-ON THE WAY OF JAVA!!!-文章分类-JDBC</title><link>http://www.blogjava.net/shuqinpeng/category/2566.html</link><description>JAVA的学习历程</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 12:16:36 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 12:16:36 GMT</pubDate><ttl>60</ttl><item><title>JDBC 指南：CallableStatement</title><link>http://www.blogjava.net/shuqinpeng/articles/9370.html</link><dc:creator>PS@JAVA</dc:creator><author>PS@JAVA</author><pubDate>Fri, 05 Aug 2005 02:18:00 GMT</pubDate><guid>http://www.blogjava.net/shuqinpeng/articles/9370.html</guid><wfw:comment>http://www.blogjava.net/shuqinpeng/comments/9370.html</wfw:comment><comments>http://www.blogjava.net/shuqinpeng/articles/9370.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shuqinpeng/comments/commentRss/9370.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shuqinpeng/services/trackbacks/9370.html</trackback:ping><description><![CDATA[7&nbsp;-&nbsp;CallableStatement <BR>本概述是从《JDBCTM&nbsp;Database&nbsp;Access&nbsp;from&nbsp;JavaTM:&nbsp;A&nbsp;Tutorial&nbsp;and&nbsp;Annotated&nbsp;Reference&nbsp;》这本书中摘引来的。JavaSoft&nbsp;目前正在准备这本书。这本书是一本教程，同时也是&nbsp;JDBC&nbsp;的重要参考手册，它将作为&nbsp;Java&nbsp;系列的组成部份在&nbsp;1997&nbsp;年春季由&nbsp;Addison-Wesley&nbsp;出版公司出版。&nbsp; <BR><BR><BR>7.1&nbsp;概述 <BR>CallableStatement&nbsp;对象为所有的&nbsp;DBMS&nbsp;提供了一种以标准形式调用已储存过程的方法。已储存过程储存在数据库中。对已储存过程的调用是&nbsp;CallableStatement&nbsp;对象所含的内容。这种调用是用一种换码语法来写的，有两种形式：一种形式带结果参数，另一种形式不带结果参数（有关换码语法的信息，参见第&nbsp;4&nbsp;节“语句”）。结果参数是一种输出&nbsp;(OUT)&nbsp;参数，是已储存过程的返回值。两种形式都可带有数量可变的输入（IN&nbsp;参数）、输出（OUT&nbsp;参数）或输入和输出（INOUT&nbsp;参数）的参数。问号将用作参数的占位符。 <BR><BR>在&nbsp;JDBC&nbsp;中调用已储存过程的语法如下所示。注意，方括号表示其间的内容是可选项；方括号本身并不是语法的组成部份。 <BR><BR>{call&nbsp;过程名[(?,&nbsp;?,&nbsp;...)]} <BR><BR>返回结果参数的过程的语法为：&nbsp; <BR><BR>{?&nbsp;=&nbsp;call&nbsp;过程名[(?,&nbsp;?,&nbsp;...)]} <BR><BR>不带参数的已储存过程的语法类似：&nbsp; <BR><BR>{call&nbsp;过程名} <BR><BR>通常，创建&nbsp;CallableStatement&nbsp;对象的人应当知道所用的&nbsp;DBMS&nbsp;是支持已储存过程的，并且知道这些过程都是些什么。然而，如果需要检查，多种&nbsp;DatabaseMetaData&nbsp;方法都可以提供这样的信息。例如，如果&nbsp;DBMS&nbsp;支持已储存过程的调用，则&nbsp;supportsStoredProcedures&nbsp;方法将返回&nbsp;true，而&nbsp;getProcedures&nbsp;方法将返回对已储存过程的描述。 <BR><BR>CallableStatement&nbsp;继承&nbsp;Statement&nbsp;的方法（它们用于处理一般的&nbsp;SQL&nbsp;语句），还继承了&nbsp;PreparedStatement&nbsp;的方法（它们用于处理&nbsp;IN&nbsp;参数）。CallableStatement&nbsp;中定义的所有方法都用于处理&nbsp;OUT&nbsp;参数或&nbsp;INOUT&nbsp;参数的输出部分：注册&nbsp;OUT&nbsp;参数的&nbsp;JDBC&nbsp;类型（一般&nbsp;SQL&nbsp;类型）、从这些参数中检索结果，或者检查所返回的值是否为&nbsp;JDBC&nbsp;NULL。 <BR><BR><BR>7.1.1&nbsp;创建&nbsp;CallableStatement&nbsp;对象 <BR>CallableStatement&nbsp;对象是用&nbsp;Connection&nbsp;方法&nbsp;prepareCall&nbsp;创建的。下例创建&nbsp;CallableStatement&nbsp;的实例，其中含有对已储存过程&nbsp;getTestData&nbsp;调用。该过程有两个变量，但不含结果参数：&nbsp; <BR><BR>CallableStatement&nbsp;cstmt&nbsp;=&nbsp;con.prepareCall( <BR>"{call&nbsp;getTestData(?,&nbsp;?)}"); <BR><BR>其中&nbsp;?&nbsp;占位符为&nbsp;IN、&nbsp;OUT&nbsp;还是&nbsp;INOUT&nbsp;参数，取决于已储存过程&nbsp;getTestData。 <BR><BR><BR>7.1.2&nbsp;IN&nbsp;和&nbsp;OUT&nbsp;参数 <BR>将&nbsp;IN&nbsp;参数传给&nbsp;CallableStatement&nbsp;对象是通过&nbsp;setXXX&nbsp;方法完成的。该方法继承自&nbsp;PreparedStatement。所传入参数的类型决定了所用的&nbsp;setXXX&nbsp;方法（例如，用&nbsp;setFloat&nbsp;来传入&nbsp;float&nbsp;值等）。 <BR><BR>如果已储存过程返回&nbsp;OUT&nbsp;参数，则在执行&nbsp;CallableStatement&nbsp;对象以前必须先注册每个&nbsp;OUT&nbsp;参数的&nbsp;JDBC&nbsp;类型（这是必需的，因为某些&nbsp;DBMS&nbsp;要求&nbsp;JDBC&nbsp;类型）。注册&nbsp;JDBC&nbsp;类型是用&nbsp;registerOutParameter&nbsp;方法来完成的。语句执行完后，CallableStatement&nbsp;的&nbsp;getXXX&nbsp;方法将取回参数值。正确的&nbsp;getXXX&nbsp;方法是为各参数所注册的&nbsp;JDBC&nbsp;类型所对应的&nbsp;Java&nbsp;类型（从&nbsp;JDBC&nbsp;类型到&nbsp;Java&nbsp;类型的标准映射见&nbsp;8.6.1&nbsp;节中的表）。换言之，&nbsp;registerOutParameter&nbsp;使用的是&nbsp;JDBC&nbsp;类型（因此它与数据库返回的&nbsp;JDBC&nbsp;类型匹配），而&nbsp;getXXX&nbsp;将之转换为&nbsp;Java&nbsp;类型。 <BR><BR>作为示例，下述代码先注册&nbsp;OUT&nbsp;参数，执行由&nbsp;cstmt&nbsp;所调用的已储存过程，然后检索在&nbsp;OUT&nbsp;参数中返回的值。方法&nbsp;getByte&nbsp;从第一个&nbsp;OUT&nbsp;参数中取出一个&nbsp;Java&nbsp;字节，而&nbsp;getBigDecimal&nbsp;从第二个&nbsp;OUT&nbsp;参数中取出一个&nbsp;BigDecimal&nbsp;对象（小数点后面带三位数）：&nbsp; <BR><BR>CallableStatement&nbsp;cstmt&nbsp;=&nbsp;con.prepareCall( <BR>"{call&nbsp;getTestData(?,&nbsp;?)}"); <BR>cstmt.registerOutParameter(1,&nbsp;java.sql.Types.TINYINT); <BR>cstmt.registerOutParameter(2,&nbsp;java.sql.Types.DECIMAL,&nbsp;3); <BR>cstmt.executeQuery(); <BR>byte&nbsp;x&nbsp;=&nbsp;cstmt.getByte(1); <BR>java.math.BigDecimal&nbsp;n&nbsp;=&nbsp;cstmt.getBigDecimal(2,&nbsp;3); <BR><BR>CallableStatement&nbsp;与&nbsp;ResultSet&nbsp;不同，它不提供用增量方式检索大&nbsp;OUT&nbsp;值的特殊机制。 <BR><BR><BR>7.1.3&nbsp;INOUT&nbsp;参数 <BR>既支持输入又接受输出的参数（INOUT&nbsp;参数）除了调用&nbsp;registerOutParameter&nbsp;方法外，还要求调用适当的&nbsp;setXXX&nbsp;方法（该方法是从&nbsp;PreparedStatement&nbsp;继承来的）。setXXX&nbsp;方法将参数值设置为输入参数，而&nbsp;registerOutParameter&nbsp;方法将它的&nbsp;JDBC&nbsp;类型注册为输出参数。setXXX&nbsp;方法提供一个&nbsp;Java&nbsp;值，而驱动程序先把这个值转换为&nbsp;JDBC&nbsp;值，然后将它送到数据库中。 <BR><BR>这种&nbsp;IN&nbsp;值的&nbsp;JDBC&nbsp;类型和提供给&nbsp;registerOutParameter&nbsp;方法的&nbsp;JDBC&nbsp;类型应该相同。然后，要检索输出值，就要用对应的&nbsp;getXXX&nbsp;方法。例如，Java&nbsp;类型为&nbsp;byte&nbsp;的参数应该使用方法&nbsp;setByte&nbsp;来赋输入值。应该给&nbsp;registerOutParameter&nbsp;提供类型为&nbsp;TINYINT&nbsp;的&nbsp;JDBC&nbsp;类型，同时应使用&nbsp;getByte&nbsp;来检索输出值&nbsp;（第&nbsp;8&nbsp;节“JDBC&nbsp;和&nbsp;Java&nbsp;类型之间的映射”将给出详细信息和类型映射表）。 <BR><BR>下例假设有一个已储存过程&nbsp;reviseTotal，其唯一参数是&nbsp;INOUT&nbsp;参数。方法&nbsp;setByte&nbsp;把此参数设为&nbsp;25，驱动程序将把它作为&nbsp;JDBC&nbsp;TINYINT&nbsp;类型送到数据库中。接着，registerOutParameter&nbsp;将该参数注册为&nbsp;JDBC&nbsp;TINYINT。执行完该已储存过程后，将返回一个新的&nbsp;JDBC&nbsp;TINYINT&nbsp;值。方法&nbsp;getByte&nbsp;将把这个新值作为&nbsp;Java&nbsp;byte&nbsp;类型检索。 <BR><BR>CallableStatement&nbsp;cstmt&nbsp;=&nbsp;con.prepareCall( <BR>"{call&nbsp;reviseTotal(?)}"); <BR>cstmt.setByte(1,&nbsp;25); <BR>cstmt.registerOutParameter(1,&nbsp;java.sql.Types.TINYINT); <BR>cstmt.executeUpdate(); <BR>byte&nbsp;x&nbsp;=&nbsp;cstmt.getByte(1); <BR><BR>7.1.4&nbsp;先检索结果，再检索&nbsp;OUT&nbsp;参数 <BR>由于某些&nbsp;DBMS&nbsp;的限制，为了实现最大的可移植性，建议先检索由执行&nbsp;CallableStatement&nbsp;对象所产生的结果，然后再用&nbsp;CallableStatement.getXXX&nbsp;方法来检索&nbsp;OUT&nbsp;参数。 <BR><BR>如果&nbsp;CallableStatement&nbsp;对象返回多个&nbsp;ResultSet&nbsp;对象（通过调用&nbsp;execute&nbsp;方法），在检索&nbsp;OUT&nbsp;参数前应先检索所有的结果。这种情况下，为确保对所有的结果都进行了访问，必须对&nbsp;Statement&nbsp;方法&nbsp;getResultSet、getUpdateCount&nbsp;和&nbsp;getMoreResults&nbsp;进行调用，直到不再有结果为止。 <BR><BR>检索完所有的结果后，就可用&nbsp;CallableStatement.getXXX&nbsp;方法来检索&nbsp;OUT&nbsp;参数中的值。 <BR><BR><BR>7.1.5&nbsp;检索作为&nbsp;OUT&nbsp;参数的&nbsp;NULL&nbsp;值 <BR>返回到&nbsp;OUT&nbsp;参数中的值可能会是&nbsp;JDBC&nbsp;NULL。当出现这种情形时，将对&nbsp;JDBC&nbsp;NULL&nbsp;值进行转换以使&nbsp;getXXX&nbsp;方法所返回的值为&nbsp;null、0&nbsp;或&nbsp;false，这取决于&nbsp;getXXX&nbsp;方法类型。对于&nbsp;ResultSet&nbsp;对象，要知道&nbsp;0&nbsp;或&nbsp;false&nbsp;是否源于&nbsp;JDBC&nbsp;NULL&nbsp;的唯一方法，是用方法&nbsp;wasNull&nbsp;进行检测。如果&nbsp;getXXX&nbsp;方法读取的最后一个值是&nbsp;JDBC&nbsp;NULL，则该方法返回&nbsp;true，否则返回&nbsp;flase。第&nbsp;5&nbsp;节“ResultSet”将给出详细信息。 <img src ="http://www.blogjava.net/shuqinpeng/aggbug/9370.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shuqinpeng/" target="_blank">PS@JAVA</a> 2005-08-05 10:18 <a href="http://www.blogjava.net/shuqinpeng/articles/9370.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC 指南：PreparedStatement</title><link>http://www.blogjava.net/shuqinpeng/articles/9369.html</link><dc:creator>PS@JAVA</dc:creator><author>PS@JAVA</author><pubDate>Fri, 05 Aug 2005 02:17:00 GMT</pubDate><guid>http://www.blogjava.net/shuqinpeng/articles/9369.html</guid><wfw:comment>http://www.blogjava.net/shuqinpeng/comments/9369.html</wfw:comment><comments>http://www.blogjava.net/shuqinpeng/articles/9369.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shuqinpeng/comments/commentRss/9369.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shuqinpeng/services/trackbacks/9369.html</trackback:ping><description><![CDATA[6&nbsp;-&nbsp;PreparedStatement <BR>本概述是从《JDBCTM&nbsp;Database&nbsp;Access&nbsp;from&nbsp;JavaTM:&nbsp;A&nbsp;Tutorial&nbsp;and&nbsp;Annotated&nbsp;Reference&nbsp;》这本书中摘引来的。JavaSoft&nbsp;目前正在准备这本书。这是一本教程，同时也是&nbsp;JDBC&nbsp;的重要参考手册，它将作为&nbsp;Java&nbsp;系列的组成部份在&nbsp;1997&nbsp;年春季由&nbsp;Addison-Wesley&nbsp;出版公司出版。&nbsp; <BR><BR><BR>6.1&nbsp;概述 <BR>该&nbsp;PreparedStatement&nbsp;接口继承&nbsp;Statement，并与之在两方面有所不同：&nbsp; <BR><BR><BR>PreparedStatement&nbsp;实例包含已编译的&nbsp;SQL&nbsp;语句。这就是使语句“准备好”。&nbsp; <BR>包含于&nbsp;PreparedStatement&nbsp;对象中的&nbsp;SQL&nbsp;语句可具有一个或多个&nbsp;IN&nbsp;参数。IN&nbsp;参数的值在&nbsp;SQL&nbsp;语句创建时未被指定。相反的，该语句为每个&nbsp;IN&nbsp;参数保留一个问号（“？”）作为占位符。每个问号的值必须在该语句执行之前，通过适当的&nbsp;setXXX&nbsp;方法来提供。&nbsp; <BR><BR>由于&nbsp;PreparedStatement&nbsp;对象已预编译过，所以其执行速度要快于&nbsp;Statement&nbsp;对象。因此，多次执行的&nbsp;SQL&nbsp;语句经常创建为&nbsp;PreparedStatement&nbsp;对象，以提高效率。 <BR><BR>作为&nbsp;Statement&nbsp;的子类，PreparedStatement&nbsp;继承了&nbsp;Statement&nbsp;的所有功能。另外它还添加了一整套方法，用于设置发送给数据库以取代&nbsp;IN&nbsp;参数占位符的值。同时，三种方法&nbsp;execute、&nbsp;executeQuery&nbsp;和&nbsp;executeUpdate&nbsp;已被更改以使之不再需要参数。这些方法的&nbsp;Statement&nbsp;形式（接受&nbsp;SQL&nbsp;语句参数的形式）不应该用于&nbsp;PreparedStatement&nbsp;对象。 <BR><BR><BR>6.1.1&nbsp;创建&nbsp;PreparedStatement&nbsp;对象 <BR>以下的代码段（其中&nbsp;con&nbsp;是&nbsp;Connection&nbsp;对象）创建包含带两个&nbsp;IN&nbsp;参数占位符的&nbsp;SQL&nbsp;语句的&nbsp;PreparedStatement&nbsp;对象：&nbsp; <BR><BR>PreparedStatement&nbsp;pstmt&nbsp;=&nbsp;con.prepareStatement( <BR>"UPDATE&nbsp;table4&nbsp;SET&nbsp;m&nbsp;=&nbsp;?&nbsp;WHERE&nbsp;x&nbsp;=&nbsp;?"); <BR><BR>pstmt&nbsp;对象包含语句&nbsp;"UPDATE&nbsp;table4&nbsp;SET&nbsp;m&nbsp;=&nbsp;?&nbsp;WHERE&nbsp;x&nbsp;=&nbsp;?"，它已发送给&nbsp;DBMS，并为执行作好了准备。 <BR><BR><BR>6.1.2&nbsp;传递&nbsp;IN&nbsp;参数 <BR>在执行&nbsp;PreparedStatement&nbsp;对象之前，必须设置每个&nbsp;?&nbsp;参数的值。这可通过调用&nbsp;setXXX&nbsp;方法来完成，其中&nbsp;XXX&nbsp;是与该参数相应的类型。例如，如果参数具有&nbsp;Java&nbsp;类型&nbsp;long，则使用的方法就是&nbsp;setLong。setXXX&nbsp;方法的第一个参数是要设置的参数的序数位置，第二个参数是设置给该参数的值。例如，以下代码将第一个参数设为&nbsp;123456789，第二个参数设为&nbsp;100000000：&nbsp; <BR><BR>pstmt.setLong(1,&nbsp;123456789); <BR>pstmt.setLong(2,&nbsp;100000000); <BR><BR>一旦设置了给定语句的参数值，就可用它多次执行该语句，直到调用&nbsp;clearParameters&nbsp;方法清除它为止。 <BR><BR>在连接的缺省模式下（启用自动提交），当语句完成时将自动提交或还原该语句。 <BR><BR>如果基本数据库和驱动程序在语句提交之后仍保持这些语句的打开状态，则同一个&nbsp;PreparedStatement&nbsp;可执行多次。如果这一点不成立，那么试图通过使用&nbsp;PreparedStatement&nbsp;对象代替&nbsp;Statement&nbsp;对象来提高性能是没有意义的。 <BR><BR>利用&nbsp;pstmt（前面创建的&nbsp;PreparedStatement&nbsp;对象），以下代码例示了如何设置两个参数占位符的值并执行&nbsp;pstmt&nbsp;10&nbsp;次。如上所述，为做到这一点，数据库不能关闭&nbsp;pstmt。在该示例中，第一个参数被设置为&nbsp;"Hi"并保持为常数。在&nbsp;for&nbsp;循环中，每次都将第二个参数设置为不同的值：从&nbsp;0&nbsp;开始，到&nbsp;9&nbsp;结束。 <BR><BR>pstmt.setString(1,&nbsp;"Hi"); <BR>for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)&nbsp;{ <BR>pstmt.setInt(2,&nbsp;i); <BR>int&nbsp;rowCount&nbsp;=&nbsp;pstmt.executeUpdate(); <BR>} <BR><BR>6.1.3&nbsp;IN&nbsp;参数中数据类型的一致性 <BR>setXXX&nbsp;方法中的&nbsp;XXX&nbsp;是&nbsp;Java&nbsp;类型。它是一种隐含的&nbsp;JDBC&nbsp;类型（一般&nbsp;SQL&nbsp;类型），因为驱动程序将把&nbsp;Java&nbsp;类型映射为相应的&nbsp;JDBC&nbsp;类型（遵循该&nbsp;JDBC&nbsp;Guide中§8.6.2&nbsp;“映射&nbsp;Java&nbsp;和&nbsp;JDBC&nbsp;类型”表中所指定的映射），并将该&nbsp;JDBC&nbsp;类型发送给数据库。例如，以下代码段将&nbsp;PreparedStatement&nbsp;对象&nbsp;pstmt&nbsp;的第二个参数设置为&nbsp;44，Java&nbsp;类型为&nbsp;short：&nbsp; <BR><BR>pstmt.setShort(2,&nbsp;44); <BR><BR>驱动程序将&nbsp;44&nbsp;作为&nbsp;JDBC&nbsp;SMALLINT&nbsp;发送给数据库，它是&nbsp;Java&nbsp;short&nbsp;类型的标准映射。 <BR><BR>程序员的责任是确保将每个&nbsp;IN&nbsp;参数的&nbsp;Java&nbsp;类型映射为与数据库所需的&nbsp;JDBC&nbsp;数据类型兼容的&nbsp;JDBC&nbsp;类型。不妨考虑数据库需要&nbsp;JDBC&nbsp;SMALLINT&nbsp;的情况。如果使用方法&nbsp;setByte&nbsp;，则驱动程序将&nbsp;JDBC&nbsp;TINYINT&nbsp;发送给数据库。这是可行的，因为许多数据库可从一种相关的类型转换为另一种类型，并且通常&nbsp;TINYINT&nbsp;可用于&nbsp;SMALLINT&nbsp;适用的任何地方。然而，对于要适用于尽可能多的数据库的应用程序，最好使用与数据库所需的确切的&nbsp;JDBC&nbsp;类型相应的&nbsp;Java&nbsp;类型。如果所需的&nbsp;JDBC&nbsp;类型是&nbsp;SMALLINT，则使用&nbsp;setShort&nbsp;代替&nbsp;setByte&nbsp;将使应用程序的可移植性更好。 <BR><BR><BR>6.1.4&nbsp;使用&nbsp;setObject <BR>程序员可使用&nbsp;setObject&nbsp;方法显式地将输入参数转换为特定的&nbsp;JDBC&nbsp;类型。该方法可以接受第三个参数，用来指定目标&nbsp;JDBC&nbsp;类型。将&nbsp;Java&nbsp;Object&nbsp;发送给数据库之前，驱动程序将把它转换为指定的&nbsp;JDBC&nbsp;类型。 <BR><BR>如果没有指定&nbsp;JDBC&nbsp;类型，驱动程序就会将&nbsp;Java&nbsp;Object&nbsp;映射到其缺省的&nbsp;JDBC&nbsp;类型（参见第&nbsp;8.6.4&nbsp;节中的表格），然后将它发送到数据库。这与常规的&nbsp;setXXX&nbsp;方法类似；在这两种情况下，驱动程序在将值发送到数据库之前，会将该值的&nbsp;Java&nbsp;类型映射为适当的&nbsp;JDBC&nbsp;类型。二者的差别在于&nbsp;setXXX&nbsp;方法使用从&nbsp;Java&nbsp;类型到&nbsp;JDBC&nbsp;类型的标准映射（参见第&nbsp;8.6.2&nbsp;节中的表格），而&nbsp;setObject&nbsp;方法使用从&nbsp;Java&nbsp;Object&nbsp;类型到&nbsp;JDBC&nbsp;类型的映射（参见第&nbsp;8.6.4&nbsp;节中的表格）。 <BR><BR>方法&nbsp;setObject&nbsp;允许接受所有&nbsp;Java&nbsp;对象的能力使应用程序更为通用，并可在运行时接受参数的输入。这种情况下，应用程序在编译时并不清楚输入类型。通过使用&nbsp;setObject，应用程序可接受所有&nbsp;Java&nbsp;对象类型作为输入，并将其转换为数据库所需的&nbsp;JDBC&nbsp;类型。第&nbsp;8.6.5&nbsp;节中的表格显示了&nbsp;setObject&nbsp;可执行的所有可能转换。 <BR><BR><BR>6.1.5&nbsp;将&nbsp;JDBC&nbsp;NULL&nbsp;作为&nbsp;IN&nbsp;参数发送 <BR>setNull&nbsp;方法允许程序员将&nbsp;JDBC&nbsp;NULL&nbsp;值作为&nbsp;IN&nbsp;参数发送给数据库。但要注意，仍然必须指定参数的&nbsp;JDBC&nbsp;类型。 <BR><BR>当把&nbsp;Java&nbsp;null&nbsp;值传递给&nbsp;setXXX&nbsp;方法时（如果它接受&nbsp;Java&nbsp;对象作为参数），也将同样把&nbsp;JDBC&nbsp;NULL&nbsp;发送到数据库。但仅当指定&nbsp;JDBC&nbsp;类型时，方法&nbsp;setObject&nbsp;才能接受&nbsp;null&nbsp;值。 <BR><BR><BR>6.1.6&nbsp;发送大的&nbsp;IN&nbsp;参数 <BR>setBytes&nbsp;和&nbsp;setString&nbsp;方法能够发送无限量的数据。但是，有时程序员更喜欢用较小的块传递大型的数据。这可通过将&nbsp;IN&nbsp;参数设置为&nbsp;Java&nbsp;输入流来完成。当语句执行时，JDBC&nbsp;驱动程序将重复调用该输入流，读取其内容并将它们当作实际参数数据传输。 <BR><BR>JDBC&nbsp;提供了三种将&nbsp;IN&nbsp;参数设置为输入流的方法：setBinaryStream&nbsp;用于含有未说明字节的流，&nbsp;setAsciiStream&nbsp;用于含有&nbsp;ASCII&nbsp;字符的流，而&nbsp;setUnicodeStream&nbsp;用于含有&nbsp;Unicode&nbsp;字符的流。因为必须指定流的总长度，所以这些方法所采用的参数比其它的&nbsp;setXXX&nbsp;方法要多一个。这很有必要，因为一些数据库在发送数据之前需要知道其总的传送大小。 <BR><BR>以下代码例示了使用流作为&nbsp;IN&nbsp;参数来发送文件内容：&nbsp; <BR><BR>java.io.File&nbsp;file&nbsp;=&nbsp;new&nbsp;java.io.File("/tmp/data"); <BR>int&nbsp;fileLength&nbsp;=&nbsp;file.length(); <BR>java.io.InputStream&nbsp;fin&nbsp;=&nbsp;new&nbsp;java.io.FileInputStream(file); <BR>java.sql.PreparedStatement&nbsp;pstmt&nbsp;=&nbsp;con.prepareStatement( <BR>"UPDATE&nbsp;Table5&nbsp;SET&nbsp;stuff&nbsp;=&nbsp;?&nbsp;WHERE&nbsp;index&nbsp;=&nbsp;4"); <BR>pstmt.setBinaryStream&nbsp;(1,&nbsp;fin,&nbsp;fileLength); <BR>pstmt.executeUpdate(); <BR><BR>当语句执行时，将反复调用输入流&nbsp;fin&nbsp;以传递其数据。 <img src ="http://www.blogjava.net/shuqinpeng/aggbug/9369.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shuqinpeng/" target="_blank">PS@JAVA</a> 2005-08-05 10:17 <a href="http://www.blogjava.net/shuqinpeng/articles/9369.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC 指南：Statement</title><link>http://www.blogjava.net/shuqinpeng/articles/9367.html</link><dc:creator>PS@JAVA</dc:creator><author>PS@JAVA</author><pubDate>Fri, 05 Aug 2005 02:16:00 GMT</pubDate><guid>http://www.blogjava.net/shuqinpeng/articles/9367.html</guid><wfw:comment>http://www.blogjava.net/shuqinpeng/comments/9367.html</wfw:comment><comments>http://www.blogjava.net/shuqinpeng/articles/9367.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shuqinpeng/comments/commentRss/9367.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shuqinpeng/services/trackbacks/9367.html</trackback:ping><description><![CDATA[<P><SPAN class=f14><SPAN class=unnamed3><FONT size=3>4 - Statement<BR>本概述是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备这本书。这是一本教程，同时也是 JDBC 的重要参考手册，它将作为 Java 系列的组成部份在 1997 年春季由 Addison-Wesley 出版公司出版。 <BR><BR><BR>4.1 概述<BR>Statement 对象用于将 SQL 语句发送到数据库中。实际上有三种 Statement 对象，它们都作为在给定连接上执行 SQL 语句的包容器：Statement、PreparedStatement（它从 Statement 继承而来）和 CallableStatement（它从 PreparedStatement 继承而来）。它们都专用于发送特定类型的 SQL 语句： Statement 对象用于执行不带参数的简单 SQL 语句；PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句；CallableStatement 对象用于执行对数据库已存储过程的调用。<BR><BR>Statement 接口提供了执行语句和获取结果的基本方法。PreparedStatement 接口添加了处理 IN 参数的方法；而 CallableStatement 添加了处理 OUT 参数的方法。<BR><BR><BR>4.1.1 创建 Statement 对象<BR>建立了到特定数据库的连接之后，就可用该连接发送 SQL 语句。Statement 对象用 Connection 的方法 createStatement 创建，如下列代码段中所示： <BR><BR>Connection con = DriverManager.getConnection(url, "sunny", "");<BR>Statement stmt = con.createStatement();<BR><BR>为了执行 Statement 对象，被发送到数据库的 SQL 语句将被作为参数提供给 Statement 的方法： <BR><BR>ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table2");<BR><BR>4.1.2 使用 Statement 对象执行语句<BR>Statement 接口提供了三种执行 SQL 语句的方法：executeQuery、executeUpdate 和 execute。使用哪一个方法由 SQL 语句所产生的内容决定。<BR><BR>方法 executeQuery 用于产生单个结果集的语句，例如 SELECT 语句。<BR><BR>方法 executeUpdate 用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL（数据定义语言）语句，例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整数，指示受影响的行数（即更新计数）。对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句，executeUpdate 的返回值总为零。<BR><BR>方法 execute 用于执行返回多个结果集、多个更新计数或二者组合的语句。因为多数程序员不会需要该高级功能，所以本概述后面将在单独一节中对其进行介绍。<BR><BR>执行语句的所有方法都将关闭所调用的 Statement 对象的当前打开结果集（如果存在）。这意味着在重新执行 Statement 对象之前，需要完成对当前 ResultSet 对象的处理。<BR><BR>应注意，继承了 Statement 接口中所有方法的 PreparedStatement 接口都有自己的 executeQuery、executeUpdate 和 execute 方法。Statement 对象本身不包含 SQL 语句，因而必须给 Statement.execute 方法提供 SQL 语句作为参数。PreparedStatement 对象并不将 SQL 语句作为参数提供给这些方法，因为它们已经包含预编译 SQL 语句。CallableStatement 对象继承这些方法的 PreparedStatement 形式。对于这些方法的 PreparedStatement 或 CallableStatement 版本，使用查询参数将抛出 SQLException。<BR><BR><BR>4.1.3 语句完成<BR>当连接处于自动提交模式时，其中所执行的语句在完成时将自动提交或还原。语句在已执行且所有结果返回时，即认为已完成。对于返回一个结果集的 executeQuery 方法，在检索完 ResultSet 对象的所有行时该语句完成。对于方法 executeUpdate，当它执行时语句即完成。但在少数调用方法 execute 的情况中，在检索所有结果集或它生成的更新计数之后语句才完成。<BR><BR>有些 DBMS 将已存储过程中的每条语句视为独立的语句；而另外一些则将整个过程视为一个复合语句。在启用自动提交时，这种差别就变得非常重要，因为它影响什么时候调用 commit 方法。在前一种情况中，每条语句单独提交；在后一种情况中，所有语句同时提交。<BR><BR><BR>4.1.4 关闭 Statement 对象<BR>Statement 对象将由 Java 垃圾收集程序自动关闭。而作为一种好的编程风格，应在不需要 Statement 对象时显式地关闭它们。这将立即释放 DBMS 资源，有助于避免潜在的内存问题。<BR><BR><BR>4.1.5 Statement 对象中的 SQL 转义语法 <BR>Statement 可包含使用 SQL 转义语法的 SQL 语句。转义语法告诉驱动程序其中的代码应该以不同方式处理。驱动程序将扫描任何转义语法，并将它转换成特定数据库可理解的代码。这使得转义语法与 DBMS 无关，并允许程序员使用在没有转义语法时不可用的功能。<BR><BR>转义子句由花括号和关键字界定： <BR><BR>{keyword . . . parameters . . . }<BR><BR>该关键字指示转义子句的类型，如下所示。<BR><BR><BR>escape 表示 LIKE 转义字符 <BR><BR><BR>字符“%”和“_”类似于 SQL LIKE 子句中的通配符（“%”匹配零个或多个字符，而“_”则匹配一个字符）。为了正确解释它们，应在其前面加上反斜杠（“\”），它是字符串中的特殊转义字符。在查询末尾包括如下语法即可指定用作转义字符的字符： <BR><BR>{escape 'escape-character'}<BR><BR><BR>例如，下列查询使用反斜杠字符作为转义字符，查找以下划线开头的标识符名： <BR><BR>stmt.executeQuery("SELECT name FROM Identifiers<BR>WHERE Id LIKE `\_%' {escape `\'};<BR><BR><BR>fn 表示标量函数<BR><BR><BR>几乎所有 DBMS 都具有标量值的数值、字符串、时间、日期、系统和转换函数。要使用这些函数，可使用如下转义语法：关键字 fn 后跟所需的函数名及其参数。例如，下列代码调用函数 concat 将两个参数连接在一起： <BR><BR>{fn concat("Hot", "Java")};<BR><BR><BR>可用下列语法获得当前数据库用户名： <BR><BR>{fn user()};<BR><BR><BR>标量函数可能由语法稍有不同的 DBMS 支持，而它们可能不被所有驱动程序支持。各种 DatabaseMetaData 方法将列出所支持的函数。例如，方法 getNumericFunctions 返回用逗号分隔的数值函数列表，而方法 getStringFunctions 将返回字符串函数，等等。<BR><BR>驱动程序将转义函数调用映射为相应的语法，或直接实现该函数。<BR><BR><BR>d、t 和 ts 表示日期和时间文字<BR><BR><BR>DBMS 用于日期、时间和时间标记文字的语法各不相同。JDBC 使用转义子句支持这些文字的语法的 ISO 标准格式。驱动程序必须将转义子句转换成 DBMS 表示。<BR><BR>例如，可用下列语法在 JDBC SQL 语句中指定日期： <BR><BR>{d `yyyy-mm-dd'}<BR><BR><BR>在该语法中，yyyy 为年代，mm 为月份，而 dd 则为日期。驱动程序将用等价的特定于 DBMS 的表示替换这个转义子句。例如，如果 '28- FEB-99' 符合基本数据库的格式，则驱动程序将用它替换 {d 1999-02-28}。<BR><BR>对于 TIME 和 TIMESTAMP 也有类似的转义子句： <BR><BR>{t `hh:mm:ss'}<BR>{ts `yyyy-mm-dd hh:mm:ss.f . . .'}<BR><BR><BR>TIMESTAMP 中的小数点后的秒（.f . . .）部分可忽略。<BR><BR><BR>call 或 ? = call 表示已存储过程<BR><BR><BR><BR>如果数据库支持已存储过程，则可从 JDBC 中调用它们，语法为： <BR><BR>{call procedure_name[(?, ?, . . .)]}<BR><BR><BR>或（其中过程返回结果参数）： <BR><BR>{? = call procedure_name[(?, ?, . . .)]}<BR><BR><BR>方括号指示其中的内容是可选的。它们不是语法的必要部分。<BR><BR>输入参数可以为文字或参数。有关详细信息，参见 JDBC 指南中第 7 节，“CallableStatement”。<BR><BR>可通过调用方法 DatabaseMetaData.supportsStoredProcedures 检查数据库是否支持已存储过程。<BR><BR><BR><BR>oj 表示外部连接<BR><BR><BR><BR>外部连接的语法为 <BR><BR>{oj outer-join}<BR><BR><BR>其中 outer-join 形式为 <BR><BR>table LEFT OUTER JOIN {table / outer-join} ON search-condition<BR><BR><BR>外部连接属于高级功能。有关它们的解释可参见 SQL 语法。JDBC 提供了三种 DatabaseMetaData 方法用于确定驱动程序支持哪些外部连接类型：supportsOuterJoins、supportsFullOuterJoins 和 supportsLimitedOuterJoins。<BR><BR><BR>方法 Statement.setEscapeProcessing 可打开或关闭转义处理；缺省状态为打开。当性能极为重要时，程序员可能想关闭它以减少处理时间。但通常它将出于打开状态。应注意： setEscapeProcessing 不适用于 PreparedStatement 对象，因为在调用该语句前它就可能已被发送到数据库。有关预编译的信息，参见 PreparedStatement。<BR><BR><BR>4.1.6 使用方法 execute<BR>execute 方法应该仅在语句能返回多个 ResultSet 对象、多个更新计数或 ResultSet 对象与更新计数的组合时使用。当执行某个已存储过程或动态执行未知 SQL 字符串（即应用程序程序员在编译时未知）时，有可能出现多个结果的情况，尽管这种情况很少见。例如，用户可能执行一个已存储过程（使用 CallableStatement 对象 - 参见第 135 页的 CallableStatement），并且该已存储过程可执行更新，然后执行选择，再进行更新，再进行选择，等等。通常使用已存储过程的人应知道它所返回的内容。<BR><BR>因为方法 execute 处理非常规情况，所以获取其结果需要一些特殊处理并不足为怪。例如，假定已知某个过程返回两个结果集，则在使用方法 execute 执行该过程后，必须调用方法 getResultSet 获得第一个结果集，然后调用适当的 getXXX 方法获取其中的值。要获得第二个结果集，需要先调用 getMoreResults 方法，然后再调用 getResultSet 方法。如果已知某个过程返回两个更新计数，则首先调用方法 getUpdateCount，然后调用 getMoreResults，并再次调用 getUpdateCount。<BR><BR>对于不知道返回内容，则情况更为复杂。如果结果是 ResultSet 对象，则方法 execute 返回 true；如果结果是 Java int，则返回 false。如果返回 int，则意味着结果是更新计数或执行的语句是 DDL 命令。在调用方法 execute 之后要做的第一件事情是调用 getResultSet 或 getUpdateCount。调用方法 getResultSet 可以获得两个或多个 ResultSet 对象中第一个对象；或调用方法 getUpdateCount 可以获得两个或多个更新计数中第一个更新计数的内容。<BR><BR>当 SQL 语句的结果不是结果集时，则方法 getResultSet 将返回 null。这可能意味着结果是一个更新计数或没有其它结果。在这种情况下，判断 null 真正含义的唯一方法是调用方法 getUpdateCount，它将返回一个整数。这个整数为调用语句所影响的行数；如果为 -1 则表示结果是结果集或没有结果。如果方法 getResultSet 已返回 null（表示结果不是 ResultSet 对象），则返回值 -1 表示没有其它结果。也就是说，当下列条件为真时表示没有结果（或没有其它结果）： <BR><BR>((stmt.getResultSet() == null) &amp;&amp; (stmt.getUpdateCount() == -1))<BR><BR>如果已经调用方法 getResultSet 并处理了它返回的 ResultSet 对象，则有必要调用方法 getMoreResults 以确定是否有其它结果集或更新计数。如果 getMoreResults 返回 true，则需要再次调用 getResultSet 来检索下一个结果集。如上所述，如果 getResultSet 返回 null，则需要调用 getUpdateCount 来检查 null 是表示结果为更新计数还是表示没有其它结果。<BR><BR>当 getMoreResults 返回 false 时，它表示该 SQL 语句返回一个更新计数或没有其它结果。因此需要调用方法 getUpdateCount 来检查它是哪一种情况。在这种情况下，当下列条件为真时表示没有其它结果： <BR><BR>((stmt.getMoreResults() == false) &amp;&amp; (stmt.getUpdateCount() == -1))<BR><BR>下面的代码演示了一种方法用来确认已访问调用方法 execute 所产生的全部结果集和更新计数： <BR><BR><BR>stmt.execute(queryStringWithUnknownResults);<BR>while (true) {<BR>int rowCount = stmt.getUpdateCount();<BR>if (rowCount &gt; 0) { // 它是更新计数<BR>System.out.println("Rows changed = " + count);<BR>stmt.getMoreResults();<BR>continue;<BR>}<BR>if (rowCount == 0) { // DDL 命令或 0 个更新<BR>System.out.println(" No rows changed or statement was DDL<BR>command");<BR>stmt.getMoreResults();<BR>continue;<BR>}<BR><BR>// 执行到这里，证明有一个结果集<BR>// 或没有其它结果<BR><BR>ResultSet rs = stmt.getResultSet;<BR>if (rs != null) {<BR>. . . // 使用元数据获得关于结果集列的信息<BR>while (rs.next()) {<BR>. . . // 处理结果<BR>stmt.getMoreResults();<BR>continue;<BR>}<BR>break; // 没有其它结果<BR></FONT></SPAN></SPAN></P><img src ="http://www.blogjava.net/shuqinpeng/aggbug/9367.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shuqinpeng/" target="_blank">PS@JAVA</a> 2005-08-05 10:16 <a href="http://www.blogjava.net/shuqinpeng/articles/9367.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC 指南：ResultSet</title><link>http://www.blogjava.net/shuqinpeng/articles/9368.html</link><dc:creator>PS@JAVA</dc:creator><author>PS@JAVA</author><pubDate>Fri, 05 Aug 2005 02:16:00 GMT</pubDate><guid>http://www.blogjava.net/shuqinpeng/articles/9368.html</guid><wfw:comment>http://www.blogjava.net/shuqinpeng/comments/9368.html</wfw:comment><comments>http://www.blogjava.net/shuqinpeng/articles/9368.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shuqinpeng/comments/commentRss/9368.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shuqinpeng/services/trackbacks/9368.html</trackback:ping><description><![CDATA[5&nbsp;-&nbsp;ResultSet <BR>本概述是从《JDBCTM&nbsp;Database&nbsp;Access&nbsp;from&nbsp;JavaTM:&nbsp;A&nbsp;Tutorial&nbsp;and&nbsp;Annotated&nbsp;Reference&nbsp;》这本书中摘引来的。JavaSoft&nbsp;目前正在准备这本书。这是一本教程，同时也是&nbsp;JDBC&nbsp;的重要参考手册，它将作为&nbsp;Java&nbsp;系列的组成部份在&nbsp;1997&nbsp;年春季由&nbsp;Addison-Wesley&nbsp;出版公司出版。&nbsp; <BR><BR><BR>5.1&nbsp;概述 <BR>ResultSet&nbsp;包含符合&nbsp;SQL&nbsp;语句中条件的所有行，并且它通过一套&nbsp;get&nbsp;方法（这些&nbsp;get&nbsp;方法可以访问当前行中的不同列）提供了对这些行中数据的访问。ResultSet.next&nbsp;方法用于移动到&nbsp;ResultSet&nbsp;中的下一行，使下一行成为当前行。 <BR><BR>结果集一般是一个表，其中有查询所返回的列标题及相应的值。例如，如果查询为&nbsp;SELECT&nbsp;a,&nbsp;b,&nbsp;c&nbsp;FROM&nbsp;Table1，则结果集将具有如下形式：&nbsp; <BR><BR><BR>a&nbsp;b&nbsp;c <BR>--------&nbsp;---------&nbsp;-------- <BR>12345&nbsp;Cupertino&nbsp;CA <BR>83472&nbsp;Redmond&nbsp;WA <BR>83492&nbsp;Boston&nbsp;MA <BR><BR><BR>下面的代码段是执行&nbsp;SQL&nbsp;语句的示例。该&nbsp;SQL&nbsp;语句将返回行集合，其中列&nbsp;1&nbsp;为&nbsp;int，列&nbsp;2&nbsp;为&nbsp;String，而列&nbsp;3&nbsp;则为字节数组：&nbsp; <BR><BR><BR>java.sql.Statement&nbsp;stmt&nbsp;=&nbsp;conn.createStatement(); <BR>ResultSet&nbsp;r&nbsp;=&nbsp;stmt.executeQuery("SELECT&nbsp;a,&nbsp;b,&nbsp;c&nbsp;FROM&nbsp;Table1"); <BR>while&nbsp;(r.next()) <BR>{ <BR>//&nbsp;打印当前行的值。 <BR>int&nbsp;i&nbsp;=&nbsp;r.getInt("a"); <BR>String&nbsp;s&nbsp;=&nbsp;r.getString("b"); <BR>float&nbsp;f&nbsp;=&nbsp;r.getFloat("c"); <BR>System.out.println("ROW&nbsp;=&nbsp;"&nbsp;+&nbsp;i&nbsp;+&nbsp;"&nbsp;"&nbsp;+&nbsp;s&nbsp;+&nbsp;"&nbsp;"&nbsp;+&nbsp;f); <BR>} <BR><BR>5.1.1&nbsp;行和光标 <BR>ResultSet&nbsp;维护指向其当前数据行的光标。每调用一次&nbsp;next&nbsp;方法，光标向下移动一行。最初它位于第一行之前，因此第一次调用&nbsp;next&nbsp;将把光标置于第一行上，使它成为当前行。随着每次调用&nbsp;next&nbsp;导致光标向下移动一行，按照从上至下的次序获取&nbsp;ResultSet&nbsp;行。 <BR><BR>在&nbsp;ResultSet&nbsp;对象或其父辈&nbsp;Statement&nbsp;对象关闭之前，光标一直保持有效。 <BR><BR>在&nbsp;SQL&nbsp;中，结果表的光标是有名字的。如果数据库允许定位更新或定位删除，则需要将光标的名字作为参数提供给更新或删除命令。可通过调用方法&nbsp;getCursorName&nbsp;获得光标名。 <BR><BR>注意：不是所有的&nbsp;DBMS&nbsp;都支持定位更新和删除。可使用&nbsp;DatabaseMetaData.supportsPositionedDelete&nbsp;和&nbsp;supportsPositionedUpdate&nbsp;方法来检查特定连接是否支持这些操作。当支持这些操作时，DBMS/驱动程序必须确保适当锁定选定行，以使定位更新不会导致更新异常或其它并发问题。 <BR><BR><BR>5.1.2&nbsp;列 <BR>方法&nbsp;getXXX&nbsp;提供了获取当前行中某列值的途径。在每一行内，可按任何次序获取列值。但为了保证可移植性，应该从左至右获取列值，并且一次性地读取列值。 <BR><BR>列名或列号可用于标识要从中获取数据的列。例如，如果&nbsp;ResultSet&nbsp;对象&nbsp;rs&nbsp;的第二列名为“title”，并将值存储为字符串，则下列任一代码将获取存储在该列中的值：&nbsp; <BR><BR>String&nbsp;s&nbsp;=&nbsp;rs.getString("title"); <BR>String&nbsp;s&nbsp;=&nbsp;rs.getString(2); <BR><BR>注意列是从左至右编号的，并且从列&nbsp;1&nbsp;开始。同时，用作&nbsp;getXXX&nbsp;方法的输入的列名不区分大小写。 <BR><BR>提供使用列名这个选项的目的是为了让在查询中指定列名的用户可使用相同的名字作为&nbsp;getXXX&nbsp;方法的参数。另一方面，如果&nbsp;select&nbsp;语句未指定列名（例如在“select&nbsp;*&nbsp;from&nbsp;table1”中或列是导出的时），则应该使用列号。这些情况下，用户将无法确切知道列名。 <BR><BR>有些情况下，SQL&nbsp;查询返回的结果集中可能有多个列具有相同的名字。如果列名用作&nbsp;getXXX&nbsp;方法的参数，则&nbsp;getXXX&nbsp;将返回第一个匹配列名的值。因而，如果多个列具有相同的名字，则需要使用列索引来确保检索了正确的列值。这时，使用列号效率要稍微高一些。 <BR><BR>关于&nbsp;ResultSet&nbsp;中列的信息，可通过调用方法&nbsp;ResultSet.getMetaData&nbsp;得到。返回的&nbsp;ResultSetMetaData&nbsp;对象将给出其&nbsp;ResultSet&nbsp;对象各列的编号、类型和属性。 <BR><BR>如果列名已知，但不知其索引，则可用方法&nbsp;findColumn&nbsp;得到其列号。 <BR><BR><BR>5.1.3&nbsp;数据类型和转换 <BR>对于&nbsp;getXXX&nbsp;方法，JDBC&nbsp;驱动程序试图将基本数据转换成指定&nbsp;Java&nbsp;类型，然后返回适合的&nbsp;Java&nbsp;值。例如，如果&nbsp;getXXX&nbsp;方法为&nbsp;getString，而基本数据库中数据类型为&nbsp;VARCHAR，则&nbsp;JDBC&nbsp;驱动程序将把&nbsp;VARCHAR&nbsp;转换成&nbsp;Java&nbsp;String。getString&nbsp;的返回值将为&nbsp;Java&nbsp;String&nbsp;对象。 <BR><BR>下表显示了允许用&nbsp;getXXX&nbsp;获取的&nbsp;JDBC&nbsp;类型及推荐用它获取的&nbsp;JDBC&nbsp;类型（通用&nbsp;SQL&nbsp;类型）。小写的&nbsp;x&nbsp;表示允许&nbsp;getXXX&nbsp;方法获取该数据类型；大写的&nbsp;X&nbsp;表示对该数据类型推荐使用&nbsp;getXXX&nbsp;方法。例如，除了&nbsp;getBytes&nbsp;和&nbsp;getBinaryStream&nbsp;之外的任何&nbsp;getXXX&nbsp;方法都可用来获取&nbsp;LONGVARCHAR&nbsp;值，但是推荐根据返回的数据类型使用&nbsp;getAsciiStream&nbsp;或&nbsp;getUnicodeStream&nbsp;方法。方法&nbsp;getObject&nbsp;将任何数据类型返回为&nbsp;Java&nbsp;Object。当基本数据类型是特定于数据库的抽象类型或当通用应用程序需要接受任何数据类型时，它是非常有用的。 <BR><BR>可使用&nbsp;ResultSet.getXXX&nbsp;方法获取常见的&nbsp;JDBC&nbsp;数据类型。&nbsp; <BR><BR><BR>5.1.4&nbsp;对非常大的行值使用流 <BR>ResultSet&nbsp;可以获取任意大的&nbsp;LONGVARBINARY&nbsp;或&nbsp;LONGVARCHAR&nbsp;数据。方法&nbsp;getBytes&nbsp;和&nbsp;getString&nbsp;将数据返回为大的块（最大为&nbsp;Statement.getMaxFieldSize&nbsp;的返回值）。但是，以较小的固定块获取非常大的数据可能会更方便，而这可通过让&nbsp;ResultSet&nbsp;类返回&nbsp;java.io.Input&nbsp;流来完成。从该流中可分块读取数据。注意：必须立即访问这些流，因为在下一次对&nbsp;ResultSet&nbsp;调用&nbsp;getXXX&nbsp;时它们将自动关闭（这是由于基本实现对大块数据访问有限制）。&nbsp; <BR><BR>JDBC&nbsp;API&nbsp;具有三个获取流的方法，分别具有不同的返回值：&nbsp; <BR><BR><BR>getBinaryStream&nbsp;返回只提供数据库原字节而不进行任何转换的流。 <BR><BR><BR>getAsciiStream&nbsp;返回提供单字节&nbsp;ASCII&nbsp;字符的流。 <BR><BR><BR>getUnicodeStream&nbsp;返回提供双字节&nbsp;Unicode&nbsp;字符的流。 <BR><BR><BR>注意：它不同于&nbsp;Java&nbsp;流，后者返回无类型字节并可（例如）通用于&nbsp;ASCII&nbsp;和&nbsp;Unicode&nbsp;字符。 <BR><BR>下列代码演示了&nbsp;getAsciiStream&nbsp;的用法：&nbsp; <BR><BR>java.sql.Statement&nbsp;stmt&nbsp;=&nbsp;con.createStatement(); <BR>ResultSet&nbsp;r&nbsp;=&nbsp;stmt.executeQuery("SELECT&nbsp;x&nbsp;FROM&nbsp;Table2"); <BR>//&nbsp;现在以&nbsp;4K&nbsp;块大小获取列&nbsp;1&nbsp;结果： <BR>byte&nbsp;buff&nbsp;=&nbsp;new&nbsp;byte[4096]; <BR>while&nbsp;(r.next())&nbsp;{ <BR>Java.io.InputStream&nbsp;fin&nbsp;=&nbsp;r.getAsciiStream(1); <BR>for&nbsp;(;;)&nbsp;{ <BR>int&nbsp;size&nbsp;=&nbsp;fin.read(buff); <BR>if&nbsp;(size&nbsp;==&nbsp;-1)&nbsp;{&nbsp;//&nbsp;到达流末尾 <BR>break; <BR>} <BR>//&nbsp;将新填充的缓冲区发送到&nbsp;ASCII&nbsp;输出流： <BR>output.write(buff,&nbsp;0,&nbsp;size); <BR>} <BR>} <BR><BR>5.1.5&nbsp;NULL&nbsp;结果值 <BR>要确定给定结果值是否是&nbsp;JDBC&nbsp;NULL，必须先读取该列，然后使用&nbsp;ResultSet.wasNull&nbsp;方法检查该次读取是否返回&nbsp;JDBC&nbsp;NULL。 <BR><BR>当使用&nbsp;ResultSet.getXXX&nbsp;方法读取&nbsp;JDBC&nbsp;NULL&nbsp;时，方法&nbsp;wasNull&nbsp;将返回下列值之一：&nbsp; <BR><BR><BR>Java&nbsp;null&nbsp;值：对于返回&nbsp;Java&nbsp;对象的&nbsp;getXXX&nbsp;方法（例如&nbsp;getString、getBigDecimal、getBytes、getDate、getTime、getTimestamp、getAsciiStream、getUnicodeStream、getBinaryStream、getObject&nbsp;等）。 <BR><BR><BR>零值：对于&nbsp;getByte、getShort、getInt、getLong、getFloat&nbsp;和&nbsp;getDouble。 <BR><BR><BR>false&nbsp;值：对于&nbsp;getBoolean。 <BR><BR><BR>5.1.6&nbsp;可选结果集或多结果集 <BR>通常使用&nbsp;executeQuery（它返回单个&nbsp;ResultSet）或&nbsp;executeUpdate（它可用于任何数据库修改语句，并返回更新行数）可执行&nbsp;SQL&nbsp;语句。但有些情况下，应用程序在执行语句之前不知道该语句是否返回结果集。此外，有些已存储过程可能返回几个不同的结果集和/或更新计数。 <BR><BR>为了适应这些情况，JDBC&nbsp;提供了一种机制，允许应用程序执行语句，然后处理由结果集和更新计数组成的任意集合。这种机制的原理是首先调用一个完全通用的&nbsp;execute&nbsp;方法，然后调用另外三个方法，getResultSet、getUpdateCount&nbsp;和&nbsp;getMoreResults。这些方法允许应用程序一次一个地研究语句结果，并确定给定结果是&nbsp;ResultSet&nbsp;还是更新计数。 <BR><BR>用户不必关闭&nbsp;ResultSet；当产生它的&nbsp;Statement&nbsp;关闭、重新执行或用于从多结果序列中获取下一个结果时，该&nbsp;ResultSet&nbsp;将被&nbsp;Statement&nbsp;自动关闭。 <img src ="http://www.blogjava.net/shuqinpeng/aggbug/9368.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shuqinpeng/" target="_blank">PS@JAVA</a> 2005-08-05 10:16 <a href="http://www.blogjava.net/shuqinpeng/articles/9368.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC 指南：DriverManager</title><link>http://www.blogjava.net/shuqinpeng/articles/9365.html</link><dc:creator>PS@JAVA</dc:creator><author>PS@JAVA</author><pubDate>Fri, 05 Aug 2005 02:12:00 GMT</pubDate><guid>http://www.blogjava.net/shuqinpeng/articles/9365.html</guid><wfw:comment>http://www.blogjava.net/shuqinpeng/comments/9365.html</wfw:comment><comments>http://www.blogjava.net/shuqinpeng/articles/9365.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shuqinpeng/comments/commentRss/9365.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shuqinpeng/services/trackbacks/9365.html</trackback:ping><description><![CDATA[3&nbsp;-&nbsp;DriverManager <BR>3.1&nbsp;概述 <BR>DriverManager&nbsp;类是&nbsp;JDBC&nbsp;的管理层，作用于用户和驱动程序之间。 <BR>它跟踪可用的驱动程序，并在数据库和相应驱动程序之间建立连接。 <BR>另外，DriverManager&nbsp;类也处理诸如驱动程序登录时间限制及登录和跟踪消息的显示等事务。 <BR><BR>对于简单的应用程序，一般程序员需要在此类中直接使用的唯一方法是&nbsp;DriverManager.getConnection。正如名称所示，该方法将建立与数据库的连接。JDBC&nbsp;允许用户调用&nbsp;DriverManager&nbsp;的方法getDriver、getDrivers&nbsp;和&nbsp;registerDriver&nbsp;及&nbsp;Driver&nbsp;的方法connect。但多数情况下，让&nbsp;DriverManager&nbsp;类管理建立连接的细节为上策。 <BR><BR><BR>3.1.1&nbsp;跟踪可用驱动程序 <BR>DriverManager&nbsp;类包含一列&nbsp;Driver&nbsp;类，它们已通过调用方法&nbsp;DriverManager.registerDriver&nbsp;对自己进行了注册。所有&nbsp;Driver类都必须包含有一个静态部分。它创建该类的实例，然后在加载该实例时&nbsp;DriverManager&nbsp;类进行注册。这样，用户正常情况下将不会直接调用&nbsp;DriverManager.registerDriver；而是在加载驱动程序时由驱动程序自动调用。加载&nbsp;Driver&nbsp;类，然后自动在&nbsp;DriverManager <BR>中注册的方式有两种：&nbsp; <BR><BR><BR>通过调用方法&nbsp;Class.forName。这将显式地加载驱动程序类。由于这与外部设置无关，因此推荐使用这种加载驱动程序的方法。以下代码加载类&nbsp;acme.db.Driver：&nbsp; <BR>Class.forName("acme.db.Driver"); <BR><BR>如果将&nbsp;acme.db.Driver&nbsp;编写为加载时创建实例，并调用以该实例为参数的DriverManager.registerDriver（本该如此），则它在DriverManager&nbsp;的驱动程序列表中，并可用于创建连接。 <BR><BR><BR>通过将驱动程序添加到&nbsp;java.lang.System&nbsp;的属性&nbsp;jdbc.drivers&nbsp;中这是一个由&nbsp;DriverManager&nbsp;类加载的驱动程序类名的列表，由冒号分隔：初始化&nbsp;DriverManager&nbsp;类时，它搜索系统属性&nbsp;jdbc.drivers， <BR>如果用户已输入了一个或多个驱动程序，则&nbsp;DriverManager&nbsp;类将试图加载它们。 <BR>以下代码说明程序员如何在&nbsp;~/.hotjava/properties&nbsp;中输入三个驱动程序类（启动时，HotJava&nbsp;将把它加载到系统属性列表中）：&nbsp; <BR>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.test.ourDriver; <BR><BR>对&nbsp;DriverManager&nbsp;方法的第一次调用将自动加载这些驱动程序类。 <BR><BR>注意：加载驱动程序的第二种方法需要持久的预设环境。如果对这一点不能保证，则调用方法&nbsp;Class.forName&nbsp;显式地加载每个驱动程序就显得更为安全。这也是引入特定驱动程序的方法，因为一旦&nbsp;DriverManager&nbsp;类被初始化，它将不再检查jdbc.drivers&nbsp;属性列表。 <BR><BR>在以上两种情况中，新加载的&nbsp;Driver&nbsp;类都要通过调用&nbsp;DriverManager.registerDriver类进行自我注册。如上所述，加载类时将自动执行这一过程。 <BR><BR>由于安全方面的原因，JDBC&nbsp;管理层将跟踪哪个类加载器提供哪个驱动程序。这样，当&nbsp;DriverManager&nbsp;类打开连接时，它仅使用本地文件系统或与发出连接请求的代码相同的类加载器提供的驱动程序。 <BR><BR><BR>3.1.2&nbsp;建立连接 <BR>加载&nbsp;Driver&nbsp;类并在&nbsp;DriverManager&nbsp;类中注册后，它们即可用来与数据库建立连接。当调用DriverManager.getConnection&nbsp;方法发出连接请求时，DriverManager&nbsp;将检查每个驱动程序，查看它是否可以建立连接。 <BR><BR>有时可能有多个&nbsp;JDBC&nbsp;驱动程序可以与给定的&nbsp;URL&nbsp;连接。例如，与给定远程数据库连接时，可以使用&nbsp;JDBC-ODBC&nbsp;桥驱动程序、JDBC&nbsp;到通用网络协议驱动程序或数据库厂商提供的驱动程序。在这种情况下测试驱动程序的顺序至关重要，因为&nbsp;DriverManager&nbsp;将使用它所找到的第一个可以成功连接到给定&nbsp;URL&nbsp;的驱动程序。 <BR><BR>首先&nbsp;DriverManager&nbsp;试图按注册的顺序使用每个驱动程序（jdbc.drivers&nbsp;中列出的驱动程序总是先注册）。它将跳过代码不可信任的驱动程序，除非加载它们的源与试图打开连接的代码的源相同。 <BR><BR>它通过轮流在每个驱动程序上调用方法&nbsp;Driver.connect，并向它们传递用户开始传递给方法DriverManager.getConnection&nbsp;的&nbsp;URL&nbsp;来对驱动程序进行测试，然后连接第一个认出该&nbsp;URL&nbsp;的驱动程序。 <BR><BR>这种方法初看起来效率不高，但由于不可能同时加载数十个驱动程序，因此每次连接实际只需几个过程调用和字符串比较。 <BR><BR>以下代码是通常情况下用驱动程序（例如&nbsp;JDBC-ODBC&nbsp;桥驱动程序）建立连接所需所有步骤的示例：&nbsp; <BR><BR>Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");&nbsp;//加载驱动程序 <BR>String&nbsp;url&nbsp;=&nbsp;"jdbc:odbc:fred"; <BR>DriverManager.getConnection(url,&nbsp;"userID",&nbsp;"passwd"); <img src ="http://www.blogjava.net/shuqinpeng/aggbug/9365.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shuqinpeng/" target="_blank">PS@JAVA</a> 2005-08-05 10:12 <a href="http://www.blogjava.net/shuqinpeng/articles/9365.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC 指南：连接</title><link>http://www.blogjava.net/shuqinpeng/articles/9364.html</link><dc:creator>PS@JAVA</dc:creator><author>PS@JAVA</author><pubDate>Fri, 05 Aug 2005 02:11:00 GMT</pubDate><guid>http://www.blogjava.net/shuqinpeng/articles/9364.html</guid><wfw:comment>http://www.blogjava.net/shuqinpeng/comments/9364.html</wfw:comment><comments>http://www.blogjava.net/shuqinpeng/articles/9364.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shuqinpeng/comments/commentRss/9364.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shuqinpeng/services/trackbacks/9364.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;内容:&nbsp;2&nbsp;-&nbsp;连接本概述是从《JDBCTM&nbsp;Database&nbsp;Access&nbsp;from&nbsp;JavaTM:&nbsp;A&nbsp;Tutorial <BR>and&nbsp;Annotated&nbsp;Reference&nbsp;》这本书中摘引来的。JavaSoft&nbsp;目前正在准备这本书。这本书是一本教程，同时也是&nbsp;JDBC&nbsp;的重要参考手册，它将作为&nbsp;Java&nbsp;系列的组成部份在&nbsp;1997&nbsp;年春季由&nbsp;Addison-Wesley&nbsp;出版公司出版。 <BR>2.1&nbsp;概述 <BR>Connection&nbsp;对象代表与数据库的连接。连接过程包括所执行的&nbsp;SQL&nbsp;语句和在该连接上所返回的结果。一个应用程序可与单个数据库有一个或多个连接，或者可与许多数据库有连接。 <BR>2.1.1&nbsp;打开连接与数据库建立连接的标准方法是调用&nbsp;DriverManager.getConnection <BR>方法。该方法接受含有某个&nbsp;URL&nbsp;的字符串。DriverManager&nbsp;类（即所谓的&nbsp;JDBC&nbsp;管理层）将尝试找到可与那个&nbsp;URL&nbsp;所代表的数据库进行连接的驱动程序。DriverManager&nbsp;类存有已注册的&nbsp;Driver&nbsp;类的清单。当调用方法&nbsp;getConnection&nbsp;时，它将检查清单中的每个驱动程序，直到找到可与&nbsp;URL&nbsp;中指定的数据库进行连接的驱动程序为止。Driver&nbsp;的方法&nbsp;connect&nbsp;使用这个&nbsp;URL&nbsp;来建立实际的连接。 <BR>用户可绕过&nbsp;JDBC&nbsp;管理层直接调用&nbsp;Driver&nbsp;方法。这在以下特殊情况下将很有用：当两个驱动器可同时连接到数据库中，而用户需要明确地选用其中特定的驱动器。但一般情况下，让&nbsp;DriverManager&nbsp;类处理打开连接这种事将更为简单。 <BR>下述代码显示如何打开一个与位于&nbsp;URL&nbsp;"jdbc:odbc:wombat"&nbsp;的数据库的连接。所用的用户标识符为&nbsp;"oboy"&nbsp;，口令为&nbsp;"12Java"：&nbsp; <BR>String&nbsp;url&nbsp;=&nbsp;"jdbc:odbc:wombat"; <BR>Connection&nbsp;con&nbsp;=&nbsp;DriverManager.getConnection(url,&nbsp;"oboy",&nbsp;"12Java"); <BR>2.1.2&nbsp;一般用法的&nbsp;URL由于&nbsp;URL&nbsp;常引起混淆，我们将先对一般&nbsp;URL&nbsp;作简单说明，然后再讨论&nbsp;JDBC&nbsp;URL。 <BR>URL（统一资源定位符）提供在&nbsp;Internet&nbsp;上定位资源所需的信息。可将它想象为一个地址。 <BR>URL&nbsp;的第一部份指定了访问信息所用的协议，后面总是跟着冒号。常用的协议有&nbsp;"ftp"（代表“文件传输协议”）和&nbsp;"http"&nbsp;（代表“超文本传输协议”）。 <BR>如果协议是&nbsp;"file"，表示资源是在某个本地文件系统上而非在&nbsp;Internet&nbsp;上（下例用于表示我们所描述的部分；它并非&nbsp;URL&nbsp;的组成部分）。 <BR>ftp://javasoft.com/docs/JDK-1_apidocs.zip <BR>http://java.sun.com/products/jdk/CurrentRelease <BR>file:/home/haroldw/docs/books/tutorial/summary.html <BR>URL&nbsp;的其余部份（冒号后面的）给出了数据资源所处位置的有关信息。如果协议是&nbsp;file，则&nbsp;URL&nbsp;的其余部份是文件的路径。对于&nbsp;ftp&nbsp;和&nbsp;http&nbsp;协议，URL&nbsp;的其余部份标识了主机并可选地给出某个更详尽的地址路径。例如，以下是&nbsp;JavaSoft&nbsp;主页的&nbsp;URL。该&nbsp;URL&nbsp;只标识了主机：&nbsp; <BR>http://java.sun.com从该主页开始浏览，就可以进到许多其它的网页中，其中之一就是 <BR>JDBC&nbsp;主页。JDBC&nbsp;主页的&nbsp;URL&nbsp;更为具体，它看起来类似：&nbsp;http://java.sun.com/products/jdbc <BR>2.1.3&nbsp;JDBC&nbsp;URL&nbsp;JDBC&nbsp;URL&nbsp;提供了一种标识数据库的方法，可以使相应的驱动程序能识别该数据库并与之建立连接。实际上，驱动程序编程员将决定用什么&nbsp;JDBC&nbsp;URL&nbsp;来标识特定的驱动程序。用户不必关心如何来形成&nbsp;JDBC&nbsp;URL；他们只须使用与所用的驱动程序一起提供的&nbsp;URL&nbsp;即可。JDBC&nbsp;的作用是提供某些约定，驱动程序编程员在构造他们的&nbsp;JDBC&nbsp;URL&nbsp;时应该遵循这些约定。 <BR>由于&nbsp;JDBC&nbsp;URL&nbsp;要与各种不同的驱动程序一起使用，因此这些约定应非常灵活。首先，它们应允许不同的驱动程序使用不同的方案来命名数据库。例如，&nbsp;odbc&nbsp;子协议允许（但并不是要求）&nbsp;URL&nbsp;含有属性值。第二，JDBC&nbsp;URL&nbsp;应允许驱动程序编程员将一切所需的信息编入其中。这样就可以让要与给定数据库对话的&nbsp;applet&nbsp;打开数据库连接，而无须要求用户去做任何系统管理工作。 <BR>第三，&nbsp;JDBC&nbsp;URL&nbsp;应允许某种程度的间接性。也就是说，JDBC&nbsp;URL&nbsp;可指向逻辑主机或数据库名，而这种逻辑主机或数据库名将由网络命名系统动态地转换为实际的名称。这可以使系统管理员不必将特定主机声明为&nbsp;JDBC&nbsp;名称的一部份。网络命名服务（例如&nbsp;DNS、&nbsp;NIS&nbsp;和&nbsp;DCE&nbsp;）有多种,而对于使用哪种命名服务并无限制。JDBC&nbsp;URL&nbsp;的标准语法如下所示。它由三部分组成，各部分间用冒号分隔：&nbsp; <BR>jdbc:&lt;&nbsp;子协议&nbsp;&gt;:&lt;&nbsp;子名称&nbsp;&gt;JDBC&nbsp;URL&nbsp;的三个部分可分解如下：&nbsp;jdbc&nbsp;─&nbsp;协议。JDBC&nbsp;URL&nbsp;中的协议总是&nbsp;jdbc。 <BR>&lt;子协议&gt;&nbsp;─&nbsp;驱动程序名或数据库连接机制（这种机制可由一个或多个驱动程序支持）的名称。子协议名的典型示例是&nbsp;"odbc"，该名称是为用于指定&nbsp;ODBC&nbsp;风格的数据资源名称的&nbsp;URL&nbsp;专门保留的。例如，为了通过&nbsp;JDBC-ODBC&nbsp;桥来访问某个数据库，可以用如下所示的&nbsp;URL：&nbsp; <BR>jdbc:odbc:fred本例中，子协议为&nbsp;"odbc"，子名称&nbsp;"fred"&nbsp;是本地ODBC&nbsp;数据资源。 <BR>如果要用网络命名服务（这样&nbsp;JDBC&nbsp;URL&nbsp;中的数据库名称不必是实际名称），则命名服务可以作为子协议。例如，可用如下所示的&nbsp;URL&nbsp;：&nbsp; <BR>jdbc:dcenaming:accounts-payable本例中，该&nbsp;URL&nbsp;指定了本地&nbsp;DCE&nbsp;命名服务应该将 <BR>数据库名称&nbsp;"accounts-payable"&nbsp;解析为更为具体的可用于连接真实数据库的名称。&lt;子名称&gt;&nbsp;─&nbsp;一种标识数据库的方法。子名称可以依不同的子协议而 <BR>变化。它还可以有子名称的子名称（含有驱动程序编程员所选的任何内部语法）。使用子名称的目的是为定位数据库提供足够的信息。前 <BR>例中，因为&nbsp;ODBC&nbsp;将提供其余部份的信息，因此用&nbsp;"fred"&nbsp;就已足够。然而，位于远程服务器上的数据库需要更多的信息。例如，如果数据库是通过&nbsp;Internet&nbsp;来访问的，则在&nbsp;JDBC&nbsp;URL&nbsp;中应将网络地址作为子名称的一部份包括进去，且必须遵循如下所示的标准&nbsp;URL&nbsp;命名约定：&nbsp; <BR>//主机名:端口/子协议假设&nbsp;"dbnet"&nbsp;是个用于将某个主机连接到&nbsp;Internet&nbsp;上的协议，则&nbsp;JDBC&nbsp;URL&nbsp;类似： <BR>jdbc:dbnet://wombat:356/fred&nbsp;2.1.4&nbsp;"odbc"&nbsp;子协议 <BR>子协议&nbsp;odbc&nbsp;是一种特殊情况。它是为用于指定&nbsp;ODBC&nbsp;风格的数据资源名称的&nbsp;URL&nbsp;而保留的，并具有下列特性：允许在子名称（数据资源名称）后面指定任意多个属性值。odbc&nbsp;子协议的完整语法为：&nbsp;jdbc:odbc:&lt;&nbsp;数据资源名称&nbsp;&gt;[;&lt;&nbsp;属性名&nbsp;&gt;=&lt;&nbsp;属性值&nbsp;&gt;]*因此，以下都是合法的&nbsp;jdbc:odbc&nbsp;名称：&nbsp;jdbc:odbc:qeor7jdbc:odbc:wombat <BR>jdbc:odbc:wombat;CacheSize=20;ExtensionCase=LOWER <BR>jdbc:odbc:qeora;UID=kgh;PWD=fooey2.1.5&nbsp;注册子协议驱动程序编程员可保留某个名称以将之用作&nbsp;JDBC&nbsp;URL&nbsp;的子协议名。 <BR>当&nbsp;DriverManager&nbsp;类将此名称加到已注册的驱动程序清单中时，为之保留该名称的驱动程序应能识别该名称并与它所标识的数据库建立连接。例如，odbc&nbsp;是为&nbsp;JDBC-&nbsp;ODBC&nbsp;桥而保留的。示例之二，假设有个&nbsp;Miracle&nbsp;公司，它可能会将&nbsp;"miracle"&nbsp;注册为连接到其&nbsp;Miracle&nbsp;DBMS&nbsp;上的&nbsp;JDBC&nbsp;驱动程序的子协议，从而使其他人都无法使用这个名称。JavaSoft&nbsp;目前作为非正式代理负责注册&nbsp;JDBC&nbsp;子协议名称。要注册某个子协议名称，请发送电子邮件到下述地址：&nbsp; <BR>jdbc@wombat.eng.sun.com2.1.6&nbsp;发送&nbsp;SQL&nbsp;语句连接一旦建立，就可用来向它所涉及的数据库传送&nbsp;SQL&nbsp;语句。JDBC对可被发送的&nbsp;SQL&nbsp;语句类型不加任何限制。这就提供了很大的灵活性，即允许使用特定的数据库语句或甚至于非&nbsp;SQL&nbsp;语句。然而，它要 <BR>求用户自己负责确保所涉及的数据库可以处理所发送的&nbsp;SQL&nbsp;语句，否则将自食其果。例如，如果某个应用程序试图向不支持储存程序的&nbsp;DBMS&nbsp;发送储存程序调用，就会失败并将抛出异常。JDBC&nbsp;要求驱动程序应至少能提供&nbsp;ANSI&nbsp;SQL-2&nbsp;Entry&nbsp;Level&nbsp;功能才可算是符合&nbsp;JDBC&nbsp;标准TM&nbsp;的。这意味着用户至少可信赖这一标准级别的功能。JDBC&nbsp;提供了三个类，用于向数据库发送&nbsp;SQL&nbsp;语句。Connection&nbsp;接口中的三个方法可用于创建这些类的实例。下面列出这些类及其创建方法：&nbsp; <BR>Statement&nbsp;─&nbsp;由方法&nbsp;createStatement&nbsp;所创建。Statement&nbsp;对象用于发送简单的&nbsp;SQL&nbsp;语句。&nbsp; <BR>PreparedStatement&nbsp;─&nbsp;由方法&nbsp;prepareStatement&nbsp;所创建。 <BR>PreparedStatement&nbsp;对象用于发送带有一个或多个输入参数（&nbsp;IN&nbsp;参数） <BR>的&nbsp;SQL&nbsp;语句。PreparedStatement&nbsp;拥有一组方法，用于设置&nbsp;IN&nbsp;参数的值。 <BR>执行语句时，这些&nbsp;IN&nbsp;参数将被送到数据库中。PreparedStatement&nbsp;的实 <BR>例扩展了&nbsp;Statement&nbsp;，因此它们都包括了&nbsp;Statement&nbsp;的方法。 <BR>PreparedStatement&nbsp;对象有可能比&nbsp;Statement&nbsp;对象的效率更高，因为它已被预编译过并存放在那以供将来使用。&nbsp; <BR>CallableStatement&nbsp;─&nbsp;由方法&nbsp;prepareCall&nbsp;所创建。CallableStatement&nbsp;对象 <BR>用于执行&nbsp;SQL&nbsp;储存程序&nbsp;─&nbsp;一组可通过名称来调用（就象函数的调用那样）的 <BR>SQL&nbsp;语句。CallableStatement&nbsp;对象从&nbsp;PreparedStatement&nbsp;中继承了用于 <BR>处理&nbsp;IN&nbsp;参数的方法，而且还增加了用于处理&nbsp;OUT&nbsp;参数和&nbsp;INOUT&nbsp;参数的方法。&nbsp; <BR>以下所列提供的方法可以快速决定应用哪个&nbsp;Connection&nbsp;方法来创建不同类型的&nbsp;SQL&nbsp;语句：&nbsp;createStatement&nbsp;方法用于： <BR>简单的&nbsp;SQL&nbsp;语句（不带参数）&nbsp;prepareStatement&nbsp;方法用于：&nbsp;带一个或多个&nbsp;IN&nbsp;参数的&nbsp;SQL&nbsp;语句&nbsp;经常被执行的简单&nbsp;SQL&nbsp;语句 <BR>prepareCall&nbsp;方法用于：&nbsp;调用已储存过程2.1.7&nbsp;事务事务由一个或多个这样的语句组成：这些语句已被执行、完成并被提交或还原。当调用方法&nbsp;commit&nbsp;或&nbsp;rollback&nbsp;时，当前事务即告就结束，另一个事务随即开始。 <BR>缺省情况下，新连接将处于自动提交模式。也就是说，当执行完语句后，将自动对那个语句调用&nbsp;commit&nbsp;方法。这种情况下，由于每个语句都是被单独提交的，因此一个事务只由一个语句组成。如果禁用自动提交模式，事务将要等到&nbsp;commit&nbsp;或&nbsp;llback&nbsp;方法被显式调用时 <BR>才结束，因此它将包括上一次调用&nbsp;commit&nbsp;或&nbsp;rollback&nbsp;方法以来所有执行过的语句。对于第二种情况，事务中的所有语句将作为组来提交或还原。方法&nbsp;commit&nbsp;使&nbsp;SQL&nbsp;语句对数据库所做的任何更改成为永久性的，它还将释放事务持有的全部锁。而方法&nbsp;rollback&nbsp;将弃去那些更改。 <BR>有时用户在另一个更改生效前不想让此更改生效。这可通过禁用自动提交并将两个更新组合在一个事务中来达到。如果两个更新都是成功 <BR>，则调用&nbsp;commit&nbsp;方法，从而使两个更新结果成为永久性的；如果其中之一或两个更新都失败了，则调用&nbsp;rollback&nbsp;方法，以将值恢复为进行更新之前的值。 <BR>大多数&nbsp;JDBC&nbsp;驱动程序都支持事务。事实上，符合&nbsp;JDBC&nbsp;的驱动程序必须支持事务。DatabaseMetaData&nbsp;给出的信息描述&nbsp;DBMS&nbsp;所提供的事务支持水平。2.1.8&nbsp;事务隔离级别如果&nbsp;DBMS&nbsp;支持事务处理，它必须有某种途径来管理两个事务同时对一个数据库进行操作时可能发生的冲突。用户可指定事务隔离级别，以指明&nbsp;DBMS&nbsp;应该花多大精力来解决潜在冲突。例如，当事务更改了某个值而第二个事务却在该更改被提交或还原前读取该值时该怎么办&nbsp;假设第一个事务被还原后，第二个事务所读取的更改值将是无效的，那么是否可允许这种冲突？&nbsp;JDBC&nbsp;用户可用以下代码来指示&nbsp;DBMS&nbsp;允许在值被提交前读取该值（“dirty&nbsp;读取”），其中&nbsp;con&nbsp;是当前连接：&nbsp; <BR>con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED); <BR>事务隔离级别越高，为避免冲突所花的精力也就越多。Connection&nbsp;接口定义了五级，其中最低级别指定了根本就不支持事务，而最高级别则指定当事务在对某个数据库进行操作时，任何其它事务不得对那个事务正在读取的数据进行任何更改。通常，隔离级别越高，应用程序执行的速度也就越慢（由于用于锁定的资源耗费增加了，而用户间的并发操作减少了）。在决定采用什么隔离级别时，开发人员必须在性能需求和数据一致性需求之间进行权衡。当然，实际所能支持的级别取决于所涉及的&nbsp;DBMS&nbsp;的功能。 <BR>当创建&nbsp;Connection&nbsp;对象时，其事务隔离级别取决于驱动程序，但通常是所涉及的数据库的缺省值。用户可通过调用&nbsp;setIsolationLevel方法来更改事务隔离级别。新的级别将在该连接过程的剩余时间内生效。要想只改变一个事务的事务隔离级别，必须在该事务开始前进行设置，并在该事务结束后进行复位。我们不提倡在事务的中途对事务隔离级别进行更改，因为这将立即触发&nbsp;commit&nbsp;方法的调用，使在此之前所作的任何更改变成永久性的。<img src ="http://www.blogjava.net/shuqinpeng/aggbug/9364.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shuqinpeng/" target="_blank">PS@JAVA</a> 2005-08-05 10:11 <a href="http://www.blogjava.net/shuqinpeng/articles/9364.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC 指南：介绍</title><link>http://www.blogjava.net/shuqinpeng/articles/9363.html</link><dc:creator>PS@JAVA</dc:creator><author>PS@JAVA</author><pubDate>Fri, 05 Aug 2005 02:10:00 GMT</pubDate><guid>http://www.blogjava.net/shuqinpeng/articles/9363.html</guid><wfw:comment>http://www.blogjava.net/shuqinpeng/comments/9363.html</wfw:comment><comments>http://www.blogjava.net/shuqinpeng/articles/9363.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/shuqinpeng/comments/commentRss/9363.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/shuqinpeng/services/trackbacks/9363.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;本简介是从《JDBCTM&nbsp;Database&nbsp;Access&nbsp;from&nbsp;JavaTM:&nbsp;A&nbsp;Tutorial&nbsp;and&nbsp;Annotated&nbsp;Reference&nbsp;》这本书中摘引来的。 <BR>JavaSoft&nbsp;目前正在准备这本书。这是一本教程，同时也是&nbsp;JDBC&nbsp;的重要参考手册，它将作为&nbsp;Java&nbsp;系列的组成部份在&nbsp;1997&nbsp;年春季由&nbsp;Addison-Wesley&nbsp;出版公司出版。&nbsp; <BR><BR><BR>1.1&nbsp;什么是&nbsp;JDBCTM？&nbsp; <BR>JDBCTM&nbsp;是一种用于执行&nbsp;SQL&nbsp;语句的&nbsp;JavaTM&nbsp;API（有意思的是，JDBC&nbsp;本身是个商标名而不是一个缩写字；然而，JDBC&nbsp;常被认为是代表&nbsp;“Java&nbsp;数据库连接&nbsp;(Java&nbsp;Database&nbsp;Connectivity)”）。它由一组用&nbsp;Java&nbsp;编程语言编写的类和接口组成。JDBC&nbsp;为工具/数据库开发人员提供了一个标准的&nbsp;API，使他们能够用纯&nbsp;Java&nbsp;API&nbsp;来编写数据库应用程序。&nbsp; <BR><BR>有了&nbsp;JDBC，向各种关系数据库发送&nbsp;SQL&nbsp;语句就是一件很容易的事。换言之，有了&nbsp;JDBC&nbsp;API，就不必为访问&nbsp;Sybase&nbsp;数据库专门写一个程序，为访问&nbsp;Oracle&nbsp;数据库又专门写一个程序，为访问&nbsp;Informix&nbsp;数据库又写另一个程序，等等。您只需用&nbsp;JDBC&nbsp;API&nbsp;写一个程序就够了，它可向相应数据库发送&nbsp;SQL&nbsp;语句。而且，使用&nbsp;Java&nbsp;编程语言编写的应用程序，就无须去忧虑要为不同的平台编写不同的应用程序。将&nbsp;Java&nbsp;和&nbsp;JDBC&nbsp;结合起来将使程序员只须写一遍程序就可让它在任何平台上运行。&nbsp; <BR><BR>Java&nbsp;具有坚固、安全、易于使用、易于理解和可从网络上自动下载等特性，是编写数据库应用程序的杰出语言。所需要的只是&nbsp;Java&nbsp;应用程序与各种不同数据库之间进行对话的方法。而&nbsp;JDBC&nbsp;正是作为此种用途的机制。&nbsp; <BR><BR>JDBC&nbsp;扩展了&nbsp;Java&nbsp;的功能。例如，用&nbsp;Java&nbsp;和&nbsp;JDBC&nbsp;API&nbsp;可以发布含有&nbsp;applet&nbsp;的网页，而该&nbsp;applet&nbsp;使用的信息可能来自远程数据库。企业也可以用&nbsp;JDBC&nbsp;通过&nbsp;Intranet&nbsp;将所有职员连到一个或多个内部数据库中（即使这些职员所用的计算机有&nbsp;Windows、&nbsp;Macintosh&nbsp;和&nbsp;UNIX&nbsp;等各种不同的操作系统）。随着越来越多的程序员开始使用&nbsp;Java&nbsp;编程语言，对从&nbsp;Java中便捷地访问数据库的要求也在日益增加。&nbsp; <BR><BR>MIS&nbsp;管理员们都喜欢&nbsp;Java&nbsp;和&nbsp;JDBC&nbsp;的结合，因为它使信息传播变得容易和经济。企业可继续使用它们安装好的数据库，并能便捷地存取信息，即使这些信息是储存在不同数据库管理系统上。新程序的开发期很短。安装和版本控制将大为简化。程序员可只编写一遍应用程序或只更新一次，然后将它放到服务器上，随后任何人就都可得到最新版本的应用程序。对于商务上的销售信息服务，&nbsp;Java&nbsp;和&nbsp;JDBC&nbsp;可为外部客户提供获取信息更新的更好方法。&nbsp; <BR><BR><BR>1.1.1&nbsp;JDBC&nbsp;的用途是什么？&nbsp; <BR>简单地说，JDBC&nbsp;可做三件事：&nbsp; <BR><BR><BR><BR>与数据库建立连接，&nbsp; <BR>发送&nbsp;SQL&nbsp;语句，&nbsp; <BR>处理结果。&nbsp; <BR><BR><BR>下列代码段给出了以上三步的基本示例：&nbsp; <BR><BR>Connection&nbsp;con&nbsp;=&nbsp;DriverManager.getConnection&nbsp;(&nbsp; <BR>"jdbc:odbc:wombat",&nbsp;"login",&nbsp;"password");&nbsp; <BR>Statement&nbsp;stmt&nbsp;=&nbsp;con.createStatement();&nbsp; <BR>ResultSet&nbsp;rs&nbsp;=&nbsp;stmt.executeQuery("SELECT&nbsp;a,&nbsp;b,&nbsp;c&nbsp;FROM&nbsp;Table1");&nbsp; <BR>while&nbsp;(rs.next())&nbsp;{&nbsp; <BR>int&nbsp;x&nbsp;=&nbsp;rs.getInt("a");&nbsp; <BR>String&nbsp;s&nbsp;=&nbsp;rs.getString("b");&nbsp; <BR>float&nbsp;f&nbsp;=&nbsp;rs.getFloat("c");&nbsp; <BR>}&nbsp; <BR><BR><BR>1.1.2&nbsp;JDBC&nbsp;是一种低级&nbsp;API&nbsp;，是高级&nbsp;API&nbsp;的基础&nbsp; <BR>JDBC&nbsp;是个“低级”接口，也就是说，它用于直接调用&nbsp;SQL&nbsp;命令。在这方面它的功能极佳，并比其它的数据库连接&nbsp;API&nbsp;易于使用，但它同时也被设计为一种基础接口，在它之上可以建立高级接口和工具。高级接口是“对用户友好的”接口，它使用的是一种更易理解和更为方便的&nbsp;API，这种&nbsp;API&nbsp;在幕后被转换为诸如&nbsp;JDBC&nbsp;这样的低级接口。在编写本文时，正在开发两种基于&nbsp;JDBC&nbsp;的高级&nbsp;API：&nbsp; <BR><BR><BR>一种用于&nbsp;Java&nbsp;的嵌入式&nbsp;SQL。至少已经有一个提供者计划编写它。DBMS&nbsp;实现&nbsp;SQL：一种专门设计来与数据库联合使用的语言。JDBC&nbsp;要求&nbsp;SQL&nbsp;语句必须作为&nbsp;String&nbsp;传给&nbsp;Java&nbsp;方法。相反，嵌入式&nbsp;SQL&nbsp;预处理器允许程序员将&nbsp;SQL&nbsp;语句直接与Java&nbsp;混在一起使用。例如，可在&nbsp;SQL&nbsp;语句中使用&nbsp;Java&nbsp;变量，用以接受或提供&nbsp;SQL&nbsp;值。然后，嵌入式&nbsp;SQL&nbsp;预处理器将通过&nbsp;JDBC&nbsp;调用把这种&nbsp;Java/SQL&nbsp;的混合物转换为&nbsp;Java。&nbsp; <BR>关系数据库表到&nbsp;Java&nbsp;类的直接映射。JavaSoft&nbsp;和其它提供者都声称要实现该&nbsp;API。在这种“对象/关系”映射中，表中的每行对应于类的一个实例，而每列的值对应于该实例的一个属性。于是，程序员可直接对&nbsp;Java&nbsp;对象进行操作；存取数据所需的&nbsp;SQL&nbsp;调用将在“掩盖下”自动生成。此外还可提供更复杂的映射，例如将多个表中的行结合进一个&nbsp;Java&nbsp;类中。&nbsp; <BR>随着人们对&nbsp;JDBC&nbsp;的兴趣日益增涨，越来越多的开发人员一直在使用基于&nbsp;JDBC&nbsp;的工具，以使程序的编写更加容易。程序员也一直在编写力图使最终用户对数据库的访问变得更为简单的应用程序。例如，应用程序可提供一个选择数据库任务的菜单。 <BR>任务被选定后，应用程序将给出提示及空白供填写执行选定任务所需的信息。所需信息输入后，应用程序将自动调用所需的SQL&nbsp;命令。在这样一种程序的协助下，即使用户根本不懂&nbsp;SQL&nbsp;的语法，也可以执行数据库任务。&nbsp; <BR><BR><BR>1.1.3&nbsp;JDBC&nbsp;与&nbsp;ODBC&nbsp;和其它&nbsp;API&nbsp;的比较&nbsp; <BR>目前，Microsoft&nbsp;的&nbsp;ODBC（开放式数据库连接）API&nbsp;可能是使用最广的、用于访问关系数据库的编程接口。它能在几乎所有平台上连接几乎所有的数据库。为什么&nbsp;Java&nbsp;不使用&nbsp;ODBC？&nbsp; <BR><BR>对这个问题的回答是：Java&nbsp;可以使用&nbsp;ODBC，但最好是在&nbsp;JDBC&nbsp;的帮助下以&nbsp;JDBC-ODBC&nbsp;桥的形式使用，这一点我们稍后再说。现在的问题已变成：“为什么需要&nbsp;JDBC”？&nbsp;回答如下：&nbsp; <BR><BR><BR>ODBC&nbsp;不适合直接在&nbsp;Java&nbsp;中使用，因为它使用&nbsp;C&nbsp;语言接口。从&nbsp;Java&nbsp;调用本地&nbsp;C&nbsp;代码在安全性、实现、坚固性和程序的自动移植性方面都有许多缺点。&nbsp; <BR>从&nbsp;ODBC&nbsp;C&nbsp;API&nbsp;到&nbsp;Java&nbsp;API&nbsp;的字面翻译是不可取的。例如，Java&nbsp;没有指针，而&nbsp;ODBC&nbsp;却对指针用得很广泛（包括很容易出错的指针&nbsp;"void&nbsp;*"）。您可以将&nbsp;JDBC&nbsp;想象成被转换为面向对象接口的&nbsp;ODBC，而面向对象的接口对&nbsp;Java&nbsp;程序员来说较 <BR>易于接收。&nbsp; <BR>ODBC&nbsp;很难学。它把简单和高级功能混在一起，而且即使对于简单的查询，其选项也极为复杂。相反，JDBC&nbsp;尽量保证简单功能的简便性，而同时在必要时允许使用高级功能。&nbsp; <BR>启用“纯&nbsp;Java&nbsp;”机制需要象&nbsp;JDBC&nbsp;这样的&nbsp;Java&nbsp;API。如果使用&nbsp;ODBC，就必须手动地将&nbsp;ODBC&nbsp;驱动程序管理器和驱动程序安装在每台客户机上。如果完全用&nbsp;Java&nbsp;编写&nbsp;JDBC&nbsp;驱动程序则&nbsp;JDBC&nbsp;代码在所有&nbsp;Java&nbsp;平台上（从网络计算机到大型机）都可以自动安装、移植并保证安全性。&nbsp; <BR>总之，JDBC&nbsp;API&nbsp;对于基本的&nbsp;SQL&nbsp;抽象和概念是一种自然的&nbsp;Java&nbsp;接口。它建立在&nbsp;ODBC&nbsp;上而不是从零开始。因此，熟悉&nbsp;ODBC&nbsp;的程序员将发现&nbsp;JDBC&nbsp;很容易使用。JDBC&nbsp;保留了&nbsp;ODBC&nbsp;的基本设计特征；事实上，两种接口都基于&nbsp;X/Open&nbsp;SQL&nbsp;CLI（调用级接口）。它们之间最大的区别在于：JDBC&nbsp;以&nbsp;Java&nbsp;风格与优点为基础并进行优化，因此更加易于使用。&nbsp; <BR><BR>最近，Microsoft&nbsp;又引进了&nbsp;ODBC&nbsp;之外的新&nbsp;API：&nbsp;RDO、&nbsp;ADO&nbsp;和&nbsp;OLE&nbsp;DB。这些设计在许多方面与&nbsp;JDBC&nbsp;是相同的，即它们都是面向对象的数据库接口且基于可在&nbsp;ODBC&nbsp;上实现的类。但在这些接口中，我们未看见有特别的功能使我们要转而选择它们来替代&nbsp;ODBC，尤其是在&nbsp;ODBC&nbsp;驱动程序已建立起较为完善的市场的情况下。它们最多也就是在&nbsp;ODBC&nbsp;上加了一种装饰而已。这并不是说&nbsp;JDBC&nbsp;不需要从其最初的版本再发展了；然而，我们觉得大部份的新功能应归入诸如前一节中所述的对象/关系映射和嵌入式&nbsp;SQL&nbsp;这样的高级&nbsp;API。&nbsp; <BR><BR><BR>1.1.4&nbsp;两层模型和三层模型&nbsp; <BR>JDBC&nbsp;API&nbsp;既支持数据库访问的两层模型，同时也支持三层模型。&nbsp; <BR><BR>在两层模型中，Java&nbsp;applet&nbsp;或应用程序将直接与数据库进行对话。这将需要一个&nbsp;JDBC&nbsp;驱动程序来与所访问的特定数据库管理系统进行通讯。用户的&nbsp;SQL&nbsp;语句被送往数据库中，而其结果将被送回给用户。数据库可以位于另一台计算机上，用户通过网络连接到上面。这就叫做客户机/服务器配置，其中用户的计算机为客户机，提供数据库的计算机为服务器。网络可以是&nbsp;Intranet（它可将公司职员连接起来），也可以是&nbsp;Internet。&nbsp; <BR><BR><BR><BR><BR><BR>在三层模型中，命令先是被发送到服务的“中间层”，然后由它将&nbsp;SQL&nbsp;语句发送给数据库。数据库对&nbsp;SQL&nbsp;语句进行处理并将结果送回到中间层，中间层再将结果送回给用户。MIS&nbsp;主管们都发现三层模型很吸引人，因为可用中间层来控制对公司数据的访问和可作的的更新的种类。中间层的另一个好处是，用户可以利用易于使用的高级&nbsp;API，而中间层将把它转换为相应的低级调用。最后，许多情况下三层结构可提供一些性能上的好处。&nbsp; <BR><BR><BR><BR><BR>到目前为止，中间层通常都用&nbsp;C&nbsp;或&nbsp;C++&nbsp;这类语言来编写，这些语言执行速度较快。然而，随着最优化编译器（它把&nbsp;Java字节代码转换为高效的特定于机器的代码）的引入，用&nbsp;Java&nbsp;来实现中间层将变得越来越实际。这将是一个很大的进步，它使人们可以充分利用&nbsp;Java&nbsp;的诸多优点（如坚固、多线程和安全等特征）。JDBC&nbsp;对于从&nbsp;Java&nbsp;的中间层来访问数据库非常重要。&nbsp; <BR><BR><BR>1.1.5&nbsp;SQL&nbsp;的一致性&nbsp; <BR>结构化查询语言&nbsp;(SQL)&nbsp;是访问关系数据库的标准语言。困难之处在于：虽然大多数的&nbsp;DBMS&nbsp;（数据库管理系统）对其基本功能都使用了标准形式的&nbsp;SQL，但它们却不符合最近为更高级的功能定义的标准&nbsp;SQL&nbsp;语法或语义。例如，并非所有的数据库都支持储存程序或外部连接，那些支持这一功能的数据库又相互不一致。人们希望&nbsp;SQL&nbsp;中真正标准的那部份能够进行扩展以包括越来越多的功能。但同时&nbsp;JDBC&nbsp;API&nbsp;又必须支持现有的&nbsp;SQL。&nbsp; <BR><BR>JDBC&nbsp;API&nbsp;解决这个问题的一种方法是允许将任何查询字符串一直传到所涉及的&nbsp;DBMS&nbsp;驱动程序上。这意味着应用程序可以使用任意多的&nbsp;SQL&nbsp;功能，但它必须冒这样的风险：有可能在某些&nbsp;DBMS&nbsp;上出错。事实上，应用程序查询甚至不一定要是&nbsp;SQL，或者说它可以是个为特定的&nbsp;DBMS&nbsp;设计的&nbsp;SQL&nbsp;的专用派生物（例如，文档或图象查询）。&nbsp; <BR><BR>JDBC&nbsp;处理&nbsp;SQL&nbsp;一致性问题的第二种方法是提供&nbsp;ODBC&nbsp;风格的转义子句。这将在&nbsp;4.1.5&nbsp;节“语句对象中的&nbsp;SQL&nbsp;转义语法”中讨论。&nbsp; <BR><BR>转义语法为几个常见的&nbsp;SQL&nbsp;分歧提供了一种标准的&nbsp;JDBC&nbsp;语法。例如，对日期文字和已储存过程的调用都有转义语法。&nbsp; <BR><BR>对于复杂的应用程序，JDBC&nbsp;用第三种方法来处理&nbsp;SQL&nbsp;的一致性问题。它利用&nbsp;DatabaseMetaData&nbsp;接口来提供关于&nbsp;DBMS&nbsp;的描述性信息，从而使应用程序能适应每个&nbsp;DBMS&nbsp;的要求和功能。&nbsp; <BR><BR>由于&nbsp;JDBC&nbsp;API&nbsp;将用作开发高级数据库访问工具和&nbsp;API&nbsp;的基础&nbsp;API，因此它还必须注意其所有上层建筑的一致性。“符合&nbsp;JDBC&nbsp;标准TM"&nbsp;代表用户可依赖的&nbsp;JDBC&nbsp;功能的标准级别。要使用这一说明，驱动程序至少必须支持&nbsp;ANSI&nbsp;SQL-2&nbsp;Entry&nbsp;Level（ANSI&nbsp;SQL-2&nbsp;代表美国国家标准局&nbsp;1992&nbsp;年所采用的标准。Entry&nbsp;Level&nbsp;代表&nbsp;SQL&nbsp;功能的特定清单）。驱动程序开发人员可用&nbsp;JDBC&nbsp;API&nbsp;所带的测试工具包来确定他们的驱动程序是否符合这些标准。&nbsp; <BR><BR>“符合&nbsp;JDBC&nbsp;标准TM”&nbsp;表示提供者的&nbsp;JDBC&nbsp;实现已经通过了&nbsp;JavaSoft&nbsp;提供的一致性测试。这些一致性测试将检查&nbsp;JDBC&nbsp;API&nbsp;中定义的所有类和方法是否都存在，并尽可能地检查程序是否具有&nbsp;SQL&nbsp;Entry&nbsp;Level&nbsp;功能。当然，这些测试并不完全，而且&nbsp;JavaSoft&nbsp;目前也无意对各提供者的实现进行标级。但这种一致性定义的确可对&nbsp;JDBC&nbsp;实现提供一定的可信度。随着越来越多的数据库提供者、连接提供者、Internet&nbsp;提供者和应用程序编程员对&nbsp;JDBC&nbsp;API&nbsp;的接受，JDBC&nbsp;也正迅速成为&nbsp;Java&nbsp;数据库访问的标准。&nbsp; <BR><BR><BR>1.2&nbsp;JDBC&nbsp;产品&nbsp; <BR>在编写本文时，有几个基于&nbsp;JDBC&nbsp;的产品已开发完毕或正在开发中。当然，本节中的信息将很快成为过时信息。因此，有关最新的信息，请查阅&nbsp;JDBC&nbsp;的网站，可通过从以下&nbsp;URL&nbsp;开始浏览找到：&nbsp; <BR><BR>http://java.sun.com/products/jdbc&nbsp; <BR><BR><BR>1.2.1&nbsp;JavaSoft&nbsp;框架&nbsp; <BR>JavaSoft&nbsp;提供三种&nbsp;JDBC&nbsp;产品组件，它们是&nbsp;Java&nbsp;开发工具包&nbsp;(JDK)&nbsp;的组成部份：&nbsp; <BR><BR><BR>JDBC&nbsp;驱动程序管理器，&nbsp; <BR><BR><BR>JDBC&nbsp;驱动程序测试工具包，和&nbsp; <BR><BR><BR>JDBC-ODBC&nbsp;桥。&nbsp; <BR><BR><BR>JDBC&nbsp;驱动程序管理器是&nbsp;JDBC&nbsp;体系结构的支柱。它实际上很小，也很简单；其主要作用是把&nbsp;Java&nbsp;应用程序连接到正确的JDBC&nbsp;驱动程序上，然后即退出。&nbsp; <BR><BR>JDBC&nbsp;驱动程序测试工具包为使&nbsp;JDBC&nbsp;驱动程序运行您的程序提供一定的可信度。只有通过&nbsp;JDBC&nbsp;驱动程序测试包的驱动程序才被认为是符合&nbsp;JDBC&nbsp;标准TM&nbsp;的。&nbsp; <BR><BR>JDBC-ODBC&nbsp;桥使&nbsp;ODBC&nbsp;驱动程序可被用作&nbsp;JDBC&nbsp;驱动程序。它的实现为&nbsp;JDBC&nbsp;的快速发展提供了一条途径，其长远目标提供一种访问某些不常见的&nbsp;DBMS（如果对这些不常见的&nbsp;DBMS&nbsp;未实现&nbsp;JDBC）&nbsp;的方法。&nbsp; <BR><BR><BR><BR><BR><BR>1.2.2&nbsp;JDBC&nbsp;驱动程序的类型&nbsp; <BR>我们目前所知晓的&nbsp;JDBC&nbsp;驱动程序可分为以下四个种类：&nbsp; <BR><BR><BR>JDBC-ODBC&nbsp;桥加&nbsp;ODBC&nbsp;驱动程序：JavaSoft&nbsp;桥产品利用&nbsp;ODBC&nbsp;驱动程序提供&nbsp;JDBC&nbsp;访问。注意，必须将&nbsp;ODBC&nbsp;二进制代码（许多情况下还包括数据库客户机代码）加载到使用该驱动程序的每个客户机上。因此，这种类型的驱动程序最适合于企业网（这种网络上客户机的安装不是主要问题），或者是用&nbsp;Java&nbsp;编写的三层结构的应用程序服务器代码。&nbsp;本地&nbsp;API&nbsp;-&nbsp;部份用&nbsp;Java&nbsp;来编写的驱动程序：&nbsp;这种类型的驱动程序把客户机&nbsp;API&nbsp;上的&nbsp;JDBC&nbsp;调用转换为&nbsp;Oracle、&nbsp;Sybase、Informix、DB2&nbsp;或其它&nbsp;DBMS&nbsp;的调用。注意，象桥驱动程序一样，这种类型的驱动程序要求将某些二进制代码加载到每台客户机上。&nbsp; <BR>JDBC&nbsp;网络纯&nbsp;Java&nbsp;驱动程序：这种驱动程序将&nbsp;JDBC&nbsp;转换为与&nbsp;DBMS&nbsp;无关的网络协议，之后这种协议又被某个服务器转换为一种&nbsp;DBMS&nbsp;协议。这种网络服务器中间件能够将它的纯&nbsp;Java&nbsp;客户机连接到多种不同的数据库上。所用的具体协议取决于提供者。通常，这是最为灵活的&nbsp;JDBC&nbsp;驱动程序。有可能所有这种解决方案的提供者都提供适合于&nbsp;Intranet&nbsp;用的产品。为了使这些产品也支持&nbsp;Internet&nbsp;访问，它们必须处理&nbsp;Web&nbsp;所提出的安全性、通过防火墙的访问等方面的额外要求。几家提供者正将&nbsp;JDBC&nbsp;驱动程序加到他们现有的数据库中间件产品中。&nbsp; <BR>本地协议纯&nbsp;Java&nbsp;驱动程序：这种类型的驱动程序将&nbsp;JDBC&nbsp;调用直接转换为&nbsp;DBMS&nbsp;所使用的网络协议。这将允许从客户机机器上直接调用&nbsp;DBMS&nbsp;服务器，是&nbsp;Intranet&nbsp;访问的一个很实用的解决方法。由于许多这样的协议都是专用的，因此数据库提供者自己将是主要来源，有几家提供者已在着手做这件事了。&nbsp; <BR>最后，我们预计第&nbsp;3、4&nbsp;类驱动程序将成为从&nbsp;JDBC&nbsp;访问数据库的首选方法。第&nbsp;1、2&nbsp;类驱动程序在直接的纯&nbsp;Java&nbsp;驱动程序还没有上市前将会作为过渡方案来使用。对第&nbsp;1、2&nbsp;类驱动程序可能会有一些变种（下表中未列出），这些变种要求有连接器，但通常这些是更加不可取的解决方案。第&nbsp;3、4&nbsp;类驱动程序提供了&nbsp;Java&nbsp;的所有优点，包括自动安装（例如，通过使用&nbsp;JDBC&nbsp;驱动程序的&nbsp;applet&nbsp;applet来下载该驱动程序）。&nbsp; <BR><BR>下表显示了这&nbsp;4&nbsp;种类型的驱动程序及其属性：&nbsp; <BR><BR><BR>驱动程序种类&nbsp;纯&nbsp;JAVA？&nbsp;网络协议&nbsp; <BR>1&nbsp;-&nbsp;JDBC-OCBC&nbsp;桥&nbsp;非&nbsp;直接&nbsp; <BR>2&nbsp;-&nbsp;基于本地&nbsp;API&nbsp;的&nbsp;非&nbsp;直接&nbsp; <BR>3&nbsp;-&nbsp;JDBC&nbsp;网络的&nbsp;是&nbsp;要求连接器&nbsp; <BR>4&nbsp;-&nbsp;基于本地协议的&nbsp;是&nbsp;直接&nbsp; <BR><BR><BR><BR>1.2.3&nbsp;JDBC&nbsp;驱动程序的获取&nbsp; <BR>在编写本文时，已有几十个属于种类的驱动程序，即可与&nbsp;Javasoft&nbsp;桥联合使用的&nbsp;1:&nbsp;ODBC&nbsp;驱动程序的驱动程序。有大约十多个属于种类&nbsp;2&nbsp;的驱动程序是以&nbsp;DBMS&nbsp;的本地&nbsp;API&nbsp;为基础编写的。只有几个属于种类&nbsp;3&nbsp;的驱动程序。目前至少有&nbsp;2&nbsp;个属于种类&nbsp;4&nbsp;的驱动程序，但到&nbsp;1997&nbsp;年底，我们预计主要的&nbsp;DBMS&nbsp;都会有种类&nbsp;4&nbsp;的驱动程序。&nbsp; <BR><BR>要获取关于驱动程序的最新信息，请查阅&nbsp;JDBC&nbsp;的网站，其网址为：&nbsp;http://&nbsp;java.sun.com/products/jdbc。提供第&nbsp;3&nbsp;种驱动程序的首批提供者是&nbsp;SCO、Open&nbsp;Horizon、Visigenic&nbsp;和&nbsp;WebLogic。JavaSoft&nbsp;和数据库连接的领先提供者&nbsp;Intersolv合作研制了&nbsp;JDBC-ODBC&nbsp;桥和&nbsp;JDBC&nbsp;驱动程序测试工具包。&nbsp; <BR><BR><BR>1.2.4&nbsp;其它产品&nbsp; <BR>各种&nbsp;JDBC&nbsp;应用程序的开发工具正在开发中。请注意查阅&nbsp;JavaSoft&nbsp;网页以得到更新信息。&nbsp;<img src ="http://www.blogjava.net/shuqinpeng/aggbug/9363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/shuqinpeng/" target="_blank">PS@JAVA</a> 2005-08-05 10:10 <a href="http://www.blogjava.net/shuqinpeng/articles/9363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>