📄 callablestatement.doc.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=gb2312">
<title></title>
</head>
<body bgcolor="#ffffff">
<table width="600">
<tr>
<td><font size="-1"><a href="introTOC.doc.html">目录</a> | <a
href="preparedstatement.doc.html">上一页</a> | <a href="mapping.doc.html">下一页</a>
</font></td>
<td align="right"><i>JDBC<sup><font size="-2">TM</font></sup> 指南:入门</i></td>
</tr>
</table>
<hr>
<p><br>
<a name="998919"></a> </p>
<h1>7 - CallableStatement</h1>
<p>本概述是从《<em>JDBC<font size="-1"><sup>TM</sup></font> Database Access from
Java<font size="-1"><sup>TM</sup></font>: A Tutorial and Annotated Reference</em>
》这本书中摘引来的。JavaSoft
目前正在准备这本书。这本书是一本教程,同时也是 JDBC
的重要参考手册,它将作为 Java 系列的组成部份在 1997 年春季由
Addison-Wesley 出版公司出版。</p>
<p><a name="997085"></a> </p>
<h2>7.1 概述</h2>
<code>
<p>CallableStatement</code> 对象为所有的 DBMS
提供了一种以标准形式调用已储存过程的方法。已储存过程储存在数据库中。对已储存过程的<em>调用</em>是
<code>CallableStatement</code>
对象所含的内容。这种调用是用一种换码语法来写的,有两种形式:一种形式带结果参数,另一种形式不带结果参数(有关换码语法的信息,参见第
<a href="statement.doc.html#999752">4</a> 节“语句”)。结果参数是一种输出
(OUT)
参数,是已储存过程的返回值。两种形式都可带有数量可变的输入(IN
参数)、输出(OUT 参数)或输入和输出(INOUT
参数)的参数。问号将用作参数的占位符。</p>
<p><a name="999016"></a>在 JDBC
中调用已储存过程的语法如下所示。注意,方括号表示其间的内容是可选项;方括号本身并不是语法的组成部份。</p>
<pre><a name="999017"></a> {call 过程名[(?, ?, ...)]}
</pre>
<p>返回结果参数的过程的语法为: </p>
<pre><a name="999019"></a> {? = call 过程名[(?, ?, ...)]}
</pre>
<p>不带参数的已储存过程的语法类似: </p>
<pre><a name="999021"></a> {call 过程名}
</pre>
<p>通常,创建 <code>CallableStatement</code> 对象的人应当知道所用的 DBMS
是支持已储存过程的,并且知道这些过程都是些什么。然而,如果需要检查,多种
<code>DatabaseMetaData</code> 方法都可以提供这样的信息。例如,如果 DBMS
支持已储存过程的调用,则<code> supportsStoredProcedures</code> 方法将返回
true,而<code> getProcedures</code> 方法将返回对已储存过程的描述。</p>
<p><code>CallableStatement</code> 继承 <code>Statement</code>
的方法(它们用于处理一般的 SQL 语句),还继承了 <code>PreparedStatement</code>
的方法(它们用于处理 IN 参数)。<code>CallableStatement</code>
中定义的所有方法都用于处理 OUT 参数或 INOUT 参数的输出部分:注册
OUT 参数的 JDBC 类型(一般 SQL
类型)、从这些参数中检索结果,或者检查所返回的值是否为<code>
JDBC</code> <code>NULL</code>。</p>
<p><a name="998954"></a> </p>
<h3>7.1.1 创建 CallableStatement 对象</h3>
<code>
<p>CallableStatement</code> 对象是用 <code>Connection</code> 方法 <code>prepareCall</code>
创建的。下例创建 <code>CallableStatement</code>
的实例,其中含有对已储存过程 <code>getTestData</code>
调用。该过程有两个变量,但不含结果参数: </p>
<pre><a name="998956"></a> CallableStatement cstmt = con.prepareCall(
<a name="998957"></a> "{call getTestData(?, ?)}");
</pre>
<p>其中 <code>?</code> 占位符为 IN、 OUT 还是 INOUT
参数,取决于已储存过程 <code>getTestData</code>。</p>
<p><a name="998959"></a> </p>
<h3>7.1.2 IN 和 OUT 参数</h3>
<p>将 IN 参数传给 <code>CallableStatement</code> 对象是通过 <code>setXXX</code>
方法完成的。该方法继承自 <code>PreparedStatement</code>。所传入参数的类型决定了所用的
<code>setXXX</code> 方法(例如,用<code> setFloat</code> 来传入 <code>float</code>
值等)。</p>
<p><a name="998961"></a>如果已储存过程返回 OUT 参数,则在执行 <code>CallableStatement</code>
对象以前必须先注册每个 OUT 参数的 JDBC
类型(这是必需的,因为某些 DBMS 要求 JDBC 类型)。注册 JDBC
类型是用 <code>registerOutParameter</code> 方法来完成的。语句执行完后,<code>CallableStatement</code>
的 <code>getXXX</code> 方法将取回参数值。正确的 <code>getXXX</code>
方法是为各参数所注册的 JDBC 类型所对应的 Java 类型(从 JDBC 类型到
Java 类型的标准映射见 <a href="mapping.doc.html#1004864">8.6.1</a>
节中的表)。换言之, <code>registerOutParameter</code> 使用的是 JDBC
类型(因此它与数据库返回的 JDBC 类型匹配),而 <code>getXXX</code>
将之转换为 Java 类型。</p>
<p><a name="998965"></a>作为示例,下述代码先注册 OUT 参数,执行由 <code>cstmt</code>
所调用的已储存过程,然后检索在 OUT 参数中返回的值。方法 <code>getByte</code>
从第一个 OUT 参数中取出一个 Java 字节,而<code> getBigDecimal</code>
从第二个 OUT 参数中取出一个 <code>BigDecimal</code>
对象(小数点后面带三位数): </p>
<pre><a name="998966"></a> CallableStatement cstmt = con.prepareCall(
<a name="998967"></a> "{call getTestData(?, ?)}");
<a
name="998968"></a> cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
<a
name="998969"></a> cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3);
<a
name="998970"></a> cstmt.executeQuery();
<a name="998971"></a> byte x = cstmt.getByte(1);
<a
name="998972"></a> java.math.BigDecimal n = cstmt.getBigDecimal(2, 3);
</pre>
<code>
<p>CallableStatement</code> 与 <code>ResultSet</code>
不同,它不提供用增量方式检索大 OUT 值的特殊机制。</p>
<p><a name="998974"></a> </p>
<h3>7.1.3 INOUT 参数</h3>
<p>既支持输入又接受输出的参数(INOUT 参数)除了调用 <code>registerOutParameter</code>
方法外,还要求调用适当的 <code>setXXX</code> 方法(该方法是从 <code>PreparedStatement</code>
继承来的)。<code>setXXX</code> 方法将参数值设置为输入参数,而 <code>registerOutParameter</code>
方法将它的 JDBC 类型注册为输出参数。<code>setXXX</code> 方法提供一个
Java 值,而驱动程序先把这个值转换为 JDBC
值,然后将它送到数据库中。</p>
<p><a name="999089"></a>这种 IN 值的 JDBC 类型和提供给 <code>registerOutParameter</code>
方法的 JDBC 类型应该相同。然后,要检索输出值,就要用对应的 <code>getXXX</code>
方法。例如,Java 类型为 <code>byte</code> 的参数应该使用方法 <code>setByte</code>
来赋输入值。应该给 <code>registerOutParameter</code> 提供类型为<code>
TINYINT</code> 的 JDBC 类型,同时应使用 <code>getByte</code> 来检索输出值
(第 <a href="mapping.doc.html#996857">8</a> 节“JDBC 和 Java
类型之间的映射”将给出详细信息和类型映射表)。</p>
<p><a name="998976"></a>下例假设有一个已储存过程 <code>reviseTotal</code>,其唯一参数是
INOUT 参数。方法 <code>setByte</code> 把此参数设为 <code>25</code>,驱动程序将把它作为
JDBC <code>TINYINT</code> 类型送到数据库中。接着,<code>registerOutParameter</code>
将该参数注册为 JDBC <code>TINYINT</code>。执行完该已储存过程后,将返回一个新的
JDBC <code>TINYINT</code> 值。方法 <code>getByte</code> 将把这个新值作为 Java <code>byte</code>
类型检索。</p>
<pre><a name="998977"></a> CallableStatement cstmt = con.prepareCall(
<a name="998978"></a> "{call reviseTotal(?)}");
<a
name="998979"></a> cstmt.setByte(1, 25);
<a name="998980"></a> cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
<a
name="998981"></a> cstmt.executeUpdate();
<a name="998982"></a> byte x = cstmt.getByte(1);
</pre>
<a name="998983"></a>
<h3>7.1.4 先检索结果,再检索 OUT 参数</h3>
<p>由于某些 DBMS
的限制,为了实现最大的可移植性,建议先检索由执行 <code>CallableStatement</code>
对象所产生的结果,然后再用 <code>CallableStatement.getXXX</code>
方法来检索 OUT 参数。</p>
<p><a name="998985"></a>如果 <code>CallableStatement</code> 对象返回多个 <code>ResultSet</code>
对象(通过调用 <code>execute</code> 方法),在检索 OUT
参数前应先检索所有的结果。这种情况下,为确保对所有的结果都进行了访问,必须对
<code>Statement</code> 方法 <code>getResultSet</code>、<code>getUpdateCount</code> 和 <code>getMoreResults</code>
进行调用,直到不再有结果为止。</p>
<p><a name="998986"></a>检索完所有的结果后,就可用 <code>CallableStatement</code>.<code>getXXX</code>
方法来检索 OUT 参数中的值。</p>
<p><a name="998987"></a> </p>
<h3>7.1.5 检索作为 OUT 参数的 NULL 值</h3>
<p>返回到 OUT 参数中的值可能会是 <code>JDBC</code> <code>NULL</code>。当出现这种情形时,将对
<code>JDBC</code> <code>NULL</code> 值进行转换以使 <code>getXXX</code>
方法所返回的值为 <code>null</code>、<code>0</code> 或 <code>false</code>,这取决于
<code>getXXX</code> 方法类型。对于 <code>ResultSet</code> 对象,要知道 <code>0</code>
或 <code>false</code> 是否源于 <code>JDBC</code> <code>NULL</code>
的唯一方法,是用方法 <code>wasNull</code> 进行检测。如果 <code>getXXX</code>
方法读取的最后一个值是 <code>JDBC</code> <code>NULL</code>,则该方法返回<code>
true</code>,否则返回 <code>flase</code>。第 <a href="resultset.doc.html#1002724">5</a>
节“ResultSet”将给出详细信息。</p>
<pre><a name="997998"></a>
</pre>
<p><br>
</p>
<hr>
<font size="-1"><a href="introTOC.doc.html">
<p>目录</a> | <a href="preparedstatement.doc.html">上一页</a> | <a
href="mapping.doc.html">下一页</a> </font></p>
<hr>
<address>
<a href="mailto:jdbc@wombat.eng.sun.com">jdbc@wombat.eng.sun.com</a> 或 <a
href="mailto:jdbc-odbc@wombat.eng.sun.com">jdbc-odbc@wombat.eng.sun.com</a>
</address>
<a href="copyright.doc.html"><font size="-1"><i>
<p>版权所有 © 1996, 1997 Sun Microsystems, Inc. 保留所有权利</i></font>。</a><!-- HTML generated by dkramer on March 14, 1997 -->
</p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -