📄 mapping.doc.html
字号:
<li><code>java.sql.Date</code>,对应于 SQL <code>DATE</code> 信息。<code>java.util.Date</code>
基本类中的小时、分钟和秒都设为 0。<br>
<br>
<a name="1008245"></a> </li>
<li><code>java.sql.Time</code>,对应于 SQL <code>TIME</code> 信息。<code>java.util.Date</code>
基本类中的年、月、日域设为 1970 年 1 月 1 日。这是 Java
纪元的“零”日期。<br>
<br>
<a name="1008246"></a> </li>
<li><code>java.sql.Timestamp</code>,对应于 SQL <code>TIMESTAMP</code>
信息。该类扩展了 <code>java.util.Date</code>,添加了纳秒域。<br>
<br>
</li>
</ul>
<p><a name="1008247"></a></p>
<p>所有这三个与时间有关的 JDBC 类都是 <code>java.util.Date</code>
的子类,因此它们可用在任何可以使用 <code>java.util.Date</code>
的地方。例如,国际化 (internationalization) 方法将 <code>java.util.Date</code>
对象用作变量,因此可将这三个与时间有关的 JDBC
类中任何一个的实例作为参数传给国际化方法。</p>
<p><a name="1008248"></a>JDBC <code>Timestamp</code>
对象除了具有其父类的日期和时间成份外,还有一个独立的纳秒组件。如果将
<code>java.sql.Timestamp</code> 对象用于需要 <code>java.util.Date</code>
对象的地方,则纳秒组件将丢失。但由于是以毫秒的精度来储存 j<code>ava.util.Date</code>
对象的,因此将 <code>java.sql.Timestamp</code> 对象转换为 <code>java.util.Date</code>
对象时可以保持这样的精度。这可通过将纳秒组件中的纳秒转换为毫秒(用纳秒数除以
1,000,000)并将之添到 <code>java.util.Date</code>
对象中来实现。转换中可能丢失高达 999,999 纳秒,但所产生的 <code>java.util.Date</code>
对象将可精确到毫秒以内。</p>
<p><a name="1008249"></a>下述代码段将 <code>java.sql.Timestamp</code>
对象转换为精度达到毫秒量级的 <code>java.util.Date</code> 对象: </p>
<pre><a name="1008250"></a> Timestamp t = new Timestamp(100, 0, 1, 15, 45, 29, 987245732);
<a
name="1008251"></a> java.util.Date d;
<a name="1008252"></a> d = new java.util.Date(t.getTime() + (t.getNanos() / 1000000));
</pre>
<a name="1006473"></a>
<h2>8.4 映射示例</h2>
<p>任何情况下,当 Java
程序要从数据库中检索数据时,必须存在某种形式的映射和数据转换。大多数时候,
JDBC
程序员将在知道其目标数据库机制的情况下进行编程。例如,他们将知道数据库含有哪些表、表中每一列的数据类型。因此,他们可使用
<code>ResultSet</code>、 <code>PreparedStatement</code>和 <code>CallableStatement</code>
接口中那些与类型有关的存取方法。本节给出三个示例,描述各种情形中所要求的数据映射和转换。</p>
<p><a name="1006476"></a> </p>
<h3>8.4.1 简单的 SQL 语句</h3>
<p>在最常见的情形中,用户将执行简单的 SQL
语句,然后取回含有结果的 <code>ResultSet</code>
对象。由数据库返回并存放在 <code>ResultSet</code> 列的值,其类型为
JDBC 数据类型。调用 <code>ResultSet.getXXX</code> 方法将把该值检索为 Java
数据类型。例如,如果某个 <code>ResultSet</code> 列含有一个 JDBC <code>FLOAT</code>
值,则方法 <code>getDouble</code> 将把它检索为 Java <code>double</code>
类型。<a href="mapping.doc.html#1006739">8.6.6</a> 节所示的表显示了哪些<code>
getXXX</code> 方法可检索哪些 JDBC 类型(如果用户不知道某个 <code>ResultSet</code>
列的类型,可通过调用 <code>ResultSet.getMetaData </code>方法来获得有关信息,然后再调用
<code>ResultSetMetaData</code> 的 <code>getColumnType</code> 或 <code>getColumnTypeName</code>
方法)。以下代码段示范了如何获得结果中各列的类型名称: </p>
<pre><a name="1006766"></a> String query = "select * from Table1";
<a
name="1006767"></a> ResultSet rs = stmt.executeQuery(query);
<a name="1006768"></a> ResultSetMetaData rsmd = rs.getMetaData();
<a
name="1006769"></a> int columnCount = rsmd.getColumnCount();
<a name="1006770"></a> for (int i = 1; i <= columnCount; i++) {
<a
name="1006771"></a> String s = rsmd.getColumnTypeName(i);
<a name="1006776"></a> System.out.println ("Column " + i + " is type " + s);
<a
name="1006777"></a> }
</pre>
<a name="1008288">
<h3>8.4.2 带 IN 参数的 SQL 语句</h3>
<p>在另一个可能的情况中,用户将发送带输入参数的 SQL
语句。这种情况下,用户通过调用 <code>PreparedStatement.setXXX</code>
方法为每个输入参数赋值。例如, <code>PreparedStatement.setLong(1, 2345678)</code>
将把值 <code>2345678</code> 作为 Java <code>的 long</code>
类型赋给第一个参数。为了将 <code>2345678</code>
到数据库中,驱动程序将把它转换为 JDBC <code>BIGINT</code>。驱动程序将把哪种
JDBC 类型送到数据库中是由 Java 类型到 JDBC
类型的标准映射所决定的,如 </a><a href="mapping.doc.html#1004752">8.6.2</a>
节中的表所示。</p>
<p><a name="1006486"></a> </p>
<h3>8.4.3 带 OUT 参数的 SQL 语句</h3>
<p>还有一个情况是,用户要调用已存储过程,将值赋给其 INOUT
参数,从结果中检索值,然后从参数中检索值。这种情形极为少见且相当复杂,但它却不失为映射和数据转换的好范例。</p>
<p>这种情况下,首先要做的是用 <code>PreparedStatement.setXXX</code> 方法对
INOUT
参数赋值。此外,由于这些参数同时也用于输出,因此程序员必须为每个参数注册
JDBC 类型,该类型是数据库所要返回给该参数的值的 JDBC
类型。这可用 <code>CallableStatement.registerOutParameter</code>
方法来完成,后者接受在类 <code>Types</code> 中所定义的 JDBC
类型作为其变量。程序员可以用 <code>ResultSet.getXXX</code>
方法系列来检索返回给<code>ResultSet</code> 对象的结果,用 <code>CallableStatement.getXXX</code>
方法系列来检索存放在输出参数中的值。</p>
<p><a name="1006489"></a>用于 <code>ResultSet</code>.<code>getXXX</code> 方法的 <code>XXX</code>
类型在某些情况下非常灵活。<a href="mapping.doc.html#1006739">8.6.6</a>
节中所示的表显示了哪些 <code>ResultSet</code>.<code>getXXX</code>
方法可用于检索哪些 JDBC 类型。</p>
<p><a name="1006493"></a>用于 <code>CallableStatement</code>.<code>getXXX</code>
方法的<code> XXX</code> 类型必须映射为那个参数所注册的 JDBC
类型。例如,如果数据库应返回类型为 <code>JDBC</code> <code>REAL</code>
的输出值,则该参数应被注册为 <code>java.sql.Types.REAL</code>。因此,要检索该
<code>JDBC</code> <code>REAL</code> 值,必须调用 <code>CallableStatement.getFloat</code>
方法(从 JDBC 类型到 Java 类型的映射在 <a href="mapping.doc.html#1004864">8.6.1</a>
节中的表中给出)。方法 <code>getFloat</code>
先把储存在输出参数中的值从 JDBC <code>REAL</code> 类型转换为 Java <code>float</code>
类型,然后将它返回。为了适应各种数据库和使应用程序具有更高的可移植性,建议先检索
<code>ResultSet</code> 对象中的值,再检索输出参数中的值。</p>
<p><a name="1006497"></a>下述代码示范的是调用名为 <code>getTestData</code>
的已存储过程。它有两个参数,且都是 INOUT 参数。首先, <code>Connection</code>
对象 <code>con</code> 将创建 <code>CallableStatement</code> 对象 <code>cstmt</code>。然后,方法
<code>setByte</code> 把第一个参数设置为 Java <code>byte</code> 类型,其值为
<code>25</code>。驱动程序将把 <code>25</code> 转换为 JDBC <code>TINYINT</code>
类型并将之送到数据库中。方法 <code>setBigDecimal</code> 用输入值 <code>83.75</code>
来设置第二个参数。驱动程序将把这个 <code>java.math.BigDecimal</code>
对象转换为 JDBC <code>NUMERIC</code> 值。接下来将这两个参数注册为 OUT
参数,第一个参数注册为 JDBC <code>TINYINT</code>
类型,第二个参数注册为小数点后面带两位数字的 JDBC <code>DECIMAL</code>
类型。执行 <code>cstmt</code> 后,就用 <code>ResultSet.getXXX</code>
方法将值从 <code>ResultSet</code> 对象中检索出来。方法 <code>getString</code>
将第一列中的值作为 Java <code>String</code> 对象获取, <code>getInt</code>
将第二列中的值作为 Java <code>int</code> 获取,<code>getInt</code>
将第三列中的值作为 Java <code>int</code> 获取。</p>
<p><a name="1006498"></a>之后, <code>CallableStatement.getXXX</code>
方法检索存放在输出参数中的值。方法 <code>getByte</code> 将 <code>JDBC</code>
<code>TINYINT</code> 检索为 Java <code>byte</code>,<code>getBigDecimal</code> 将 <code>JDBC</code>
<code>DECIMAL</code> 检索为小数点后面带有两位数字的 <code>java.math.BigDecimal</code>
对象。注意,当参数既是输入参数同时又是输出参数时,<code>setXXX</code>
方法所用的 Java 类型与 <code>getXXX</code> 方法所用的相同(正如 <code>setByte</code>
和 <code>getByte</code> 中一样)。<code>registerOutParameter</code>
方法将它注册成由 Java 类型映射来的 JDBC 类型(Java <code>byte</code>
类型映射为 JDBC <code>TINYINT</code>,如 <a href="mapping.doc.html#1004752">8.6.2</a>
节中的表所示)。</p>
<pre><a name="1006502"></a> CallableStatement cstmt = con.prepareCall(
<a name="1006503"></a> "{call getTestData(?, ?)}");
<a
name="1006504"></a> cstmt.setByte(1, 25);
<a name="1006505"></a> cstmt.setBigDecimal(2, 83.75);
<a
name="1006506"></a> // 将第一个参数注册为 JDBC TINYINT,第二个
<a
name="1006507"></a> // 参数注册为小数点后面带有两位数字的 JDBC DECIMAL 类型
<a
name="1006508"></a> cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
<a
name="1006509"></a> cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 2);
<a
name="1006510"></a> ResultSet rs = cstmt.executeUpdate();
<a name="1006511"></a> // 检索并打印结果中的值。
<a
name="1006512"></a> while(rs.next()) {
<a name="1006513"></a> String name = rs.getString(1);
<a
name="1006514"></a> int score = rs.getInt(2);
<a name="1006515"></a> int percentile = rs.getInt(3);
<a
name="1006516"></a> System.out.print("name = " + name + ", score = " + score + ", "
<a
name="1006517"></a> System.out.println("percentile = " + percentile);
<a
name="1006518"></a> // 检索输出参数中的值
<a name="1006519"></a> byte x = cstmt.getByte(1);
<a
name="1006520"></a> java.math.BigDecimal n = cstmt.getBigDecimal(2, 2);
</pre>
<p>总之,<code>CallableStatement.getXXX</code> 和 <code>PreparedStatement.setXXX</code>
方法系列中的 <code>XXX</code> 是 Java 类型。对于 <code>setXXX</code>
方法,驱动程序先把 Java 类型转换为 JDBC
类型,再把它送到数据库中(使用 <a href="mapping.doc.html#1004752">8.6.2</a>
节中的表所示的标准映射)。对于 <code>getXXX</code> 方法,
驱动程序先把数据库返回的 JDBC 类型转换为 Java 类型(用 <a
href="mapping.doc.html#1004864">8.6.1</a>
节表中所示的标准映射),再把它返回给 <code>getXXX</code> 方法。</p>
<p><a name="1006528"></a><code>registerOutParameter</code> 方法只接受 JDBC
类型的变量,而 <code>setObject</code> 方法却可接受 JDBC 类型的变量。 </p>
<p><a name="1006529"></a>注意,如果在可选的第三个变量的位置上提供了
JDBC 类型,则 <code>setObject</code> 方法将把参数值从 Java
类型显式地转换为所指定的 JDBC 类型。如果没有为<code> setObject</code>
提供目标 JDBC 类型,则将把参数值转换为 Java 类型的标准映射 JDBC
类型(如 <a href="mapping.doc.html#1004752">8.6.2</a>
节的表中所示)。在将参数送到数据库中之前,驱动程序都要进行显式或隐式转换。</p>
<p><a name="1008372"></a> </p>
<h2>8.5 动态数据存取</h2>
<p>大多数时候,用户要存取的结果和参数其数据类型在编译时是已知的。然而,有些应用程序(例如普通的浏览器或查询工具)在编译时对它们所要存取的数据库的机制并不知晓。因此,JDBC
除了支持静态数据类型存取外,还支持类型完全动态确定的数据存取。</p>
<p><a name="1008374"></a>有三种方法和一个常量可用于访问那些在编译时其数据类型尚属未知的值:
<ul>
<p><a name="1008375"></a></p>
<li><code>ResultSet.getObject </code><br>
<br>
<a name="1008376"></a> </li>
<li><code>PreparedStatement.setObject </code><br>
<br>
<a name="1008377"></a> </li>
<li><code>CallableStatement.getObject </code><br>
<br>
<a name="1008378"></a> </li>
<li><code>java.sql.Types.OTHER </code>(用作 <code>CallableStatement.registerOutParameter</code>
的一个变量) <br>
<br>
</li>
</ul>
<p><a name="1008379"></a></p>
<p>例如,如果应用程序想要接受多种类型作为其 <code>ResultSet</code>
对象中的结果,它可以使用 <code>ResultSet.getObject</code> 方法。</p>
<p><a name="1008380"></a><code>ResultSet.getObject</code> 和 <code>CallableStatement.getObject</code>
方法将值检索为 Java <code>Object</code>。由于 <code>Object</code> 是所有 Java
对象的基本类,因此可将任何 Java 类的实例检索为 <code>Object</code>
的实例。然而,以下 Java
类型是内置的“基本”类型,因此,它们不是类 <code>Object</code>
的实例: <code>boolean</code>、<code>char</code>、<code>byte</code>、<code>short</code>、<code>int</code>、<code>long</code>、
<code>float</code> 和 <code>double</code>。因此,不能用 <code>getObject</code>
方法来检索它们。然而,这些基本类型每种都有相应的可用作 wrapper
的类。这些类的实例是对象,这意味着可用 <code>ResultSet.getObject</code>
和 <code>CallableStatement.getObject</code> 方法来检索它们。<a
href="mapping.doc.html#1004791">第 67 页中的表 8.6.3 </a>显示了从 JDBC 类型到
Java <code>Object</code> 类型的映射。该表与 JDBC 类型到 Java
类型的标准映射不同:在该表中,除了 JDBC <code>TINYINT</code> 和 JDBC <code>SMALLINT</code>
类型映射为 Java 类 <code>Integer</code> 之外,每一个基本的 Java
类型都被替换为它们的 wrapper 类。</p>
<p><a name="1008384"></a>方法 <code>getObject</code> 还可用于检索用户定义的
Java 类型。随着抽象数据类型(ADT)和其它用户定义的类型在某些数据库系统中的出现,一些提供者可能会发现用
<code>getObject</code> 来检索这些类型将更方便。</p>
<p><a name="999058"></a> </p>
<h2>8.6 数据类型映射表</h2>
<p>本节含有以下表,它们是 JDBC 类型 和 Java
数据类型之间的映射关系表: </p>
<p><a name="1005569"></a> </p>
<p><a href="mapping.doc.html#1004864">8.6.1 节</a> — 从 JDBC 类型映射到 Java
类型 </p>
<p><a name="1005565"></a> </p>
<p><a name="1005566"></a><a href="mapping.doc.html#1004752">8.6.2 节</a> — 从 Java
类型映射到 JDBC 类型 </p>
<p><a name="1005570"></a> </p>
<p><a name="1005571"></a><a href="mapping.doc.html#1004791">8.6.3 节</a> ─ 从 JDBC
类型映射到 Java <code>Object</code> 类型 </p>
<p><a name="1005572"></a> </p>
<p><a name="1005573"></a><a href="mapping.doc.html#1004830">8.6.4 节 </a>─ 从 Java <code>Object</code>
类型映射到 JDBC 类型 </p>
<p><a name="1005574"></a> </p>
<p><a name="1005575"></a><a href="mapping.doc.html#1004845">8.6.5 节</a> ─ 由 <code>setObject</code>
所进行的转换 </p>
<p><a name="1005576"></a> </p>
<p><a name="1005577"></a><a href="mapping.doc.html#1006739">8.6.6 节 </a>— 由 <code>ResultSet.getXXX</code>
方法所检索的 JDBC 类型 </p>
<p><a name="1005567"></a> </p>
<p><a name="1005568"></a> </p>
<p><a name="1004864"></a> </p>
<h3>8.6.1 从 JDBC 类型映射到 Java 类型</h3>
<table Border="3">
<tr>
<th valign="top"><strong>JDBC 类型 </strong></th>
<th valign="top"><strong>Java 类型 </strong></th>
</tr>
<tr>
<td><code>CHAR </code></td>
<td><code>String </code></td>
</tr>
<tr>
<td><code>VARCHAR </code></td>
<td><code>String </code></td>
</tr>
<tr>
<td><code>LONGVARCHAR </code></td>
<td><code>String </code></td>
</tr>
<tr>
<td><code>NUMERIC </code></td>
<td><code>java.math.BigDecimal </code></td>
</tr>
<tr>
<td><code>DECIMAL </code></td>
<td><code>java.math.BigDecimal </code></td>
</tr>
<tr>
<td><code>BIT </code></td>
<td><code>boolean </code></td>
</tr>
<tr>
<td><code>TINYINT </code></td>
<td><code>byte </code></td>
</tr>
<tr>
<td><code>SMALLINT </code></td>
<td><code>short </code></td>
</tr>
<tr>
<td><code>INTEGER </code></td>
<td><code>int </code></td>
</tr>
<tr>
<td><code>BIGINT </code></td>
<td><code>long </code></td>
</tr>
<tr>
<td><code>REAL </code></td>
<td><code>float </code></td>
</tr>
<tr>
<td><code>FLOAT </code></td>
<td><code>double </code></td>
</tr>
<tr>
<td><code>DOUBLE </code></td>
<td><code>double </code></td>
</tr>
<tr>
<td><code>BINARY </code></td>
<td><code>byte[] </code></td>
</tr>
<tr>
<td><code>VARBINARY </code></td>
<td><code>byte[] </code></td>
</tr>
<tr>
<td><code>LONGVARBINARY </code></td>
<td><code>byte[] </code></td>
</tr>
<tr>
<td><code>DATE </code></td>
<td><code>java.sql.Date </code></td>
</tr>
<tr>
<td><code>TIME </code></td>
<td><code>java.sql.Time </code></td>
</tr>
<tr>
<td><code>TIMESTAMP </code></td>
<td><code>java.sql.Timestamp </code></td>
</tr>
</table>
<table>
<tr>
<td></td>
</tr>
</table>
<p><a name="1004951"></a></p>
<p>
<a name="1004745"></a>
<p>
<a name="1004746"></a>
<p>
<a name="1004747"></a>
<p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -