<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>lthu</title>
    <description></description>
    <link>http://lthu.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>Servlet和Filter的url匹配以及url-pattern详解</title>
        <author>lthu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lthu.javaeye.com">lthu</a>&nbsp;
          链接：<a href="http://lthu.javaeye.com/blog/213322" style="color:red;">http://lthu.javaeye.com/blog/213322</a>&nbsp;
          发表时间: 2008年07月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1 style="line-height: 150%; text-align: center;"><span style="font-size: medium;"><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">Servlet</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">和</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">Filter</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">的</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">url</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">匹配以及</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">url-pattern</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">详解</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"></span></span></h1>
<p class="MsoNormal" style="line-height: 150%;"><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"><span style="mso-tab-count: 1;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Servlet</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">和</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">filter</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">是</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">J2EE</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">开发中常用的技术，使用方便，配置简单，老少皆宜。估计大多数朋友都是直接配置用，也没有关心过具体的细节，今天遇到一个问题，上网查了</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">servlet</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">的规范才发现，</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">servlet</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">和</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">filter</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">中的</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">url-pattern</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">还是有一些文章在里面的，总结了一些东西，放出来供大家参考，以免遇到问题又要浪费时间。</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"></span></p>
<h2 style="line-height: 150%;"><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"><span style="mso-tab-count: 1;">&nbsp;&nbsp;&nbsp;<span style="font-size: small;"> 一，</span></span><span style="font-size: small;">servlet</span></span><span style="font-size: small;"><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Cambria;">容器对</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">url</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Cambria;">的匹配过程：</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"></span></span></h2>
<p class="MsoNormal" style="line-height: 150%;"><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"><span style="mso-tab-count: 1;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<table class="MsoNormalTable" cellspacing="0" border="1" cellpadding="0" style="background: #f2f2f2; border-collapse: collapse; mso-shading: windowtext; mso-pattern: gray-5 auto; mso-border-alt: solid #9BBB59 1.0pt; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: 1.0pt solid #9BBB59; mso-border-insidev: 1.0pt solid #9BBB59;">
<tbody>
<tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes;">
<td valign="top" width="568" style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 426.1pt; padding-top: 0cm; border: #9bbb59 1pt solid;">
<p class="MsoNormal" style="text-indent: 21pt; line-height: 150%;"><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">当一个请求发送到</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">容器的时候，容器先会将请求的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">减去当前应用上下文的</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-weight: bold;">路径</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">作为</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">的映射</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，比如我访问的是</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"><a href="http://localhost/test/aaa.html"><span style="color: #108ac6;">http://localhost/test/aaa.html</span></a></span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，我的应用上下文是</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">test</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，容器会将</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"><a href="http://localhost/test"><span style="color: #108ac6;">http://localhost/test</span></a></span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">去掉，剩下的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">/aaa.html</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">部分拿来做</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">的映射匹配。这个映射匹配过程是有顺序的，而且当有一个</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">匹配成功以后，就不会去理会剩下的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">了（</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">filter</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">不同，后文会提到）。其匹配规则和顺序如下：</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"></span></p>
<p class="MsoListParagraph" style="margin-left: 42pt; text-indent: -21pt; line-height: 150%; mso-char-indent-count: 0; mso-list: l1 level1 lfo1;"><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold; mso-fareast-font-family: Verdana; mso-bidi-font-family: Verdana;"><span style="mso-list: Ignore;">1.<span style="font: 7pt 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">精确路径匹配。例子：比如</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servletA </span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url-pattern</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">为</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"> /test</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servletB</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url-pattern</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">为</span><span style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"> <span lang="EN-US">/* </span></span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，这个时候，如果我访问的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">为</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"><a href="http://localhost/test"><span style="color: #108ac6;">http://localhost/test</span></a> </span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，这个时候容器就会先</span><span style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"> </span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">进行精确路径匹配，发现</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">/test</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">正好被</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servletA</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">精确匹配，那么就去调用</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servletA</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，也不会去理会其他的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">了。</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"></span></p>
<p class="MsoListParagraph" style="margin-left: 42pt; text-indent: -21pt; line-height: 150%; mso-char-indent-count: 0; mso-list: l1 level1 lfo1;"><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold; mso-fareast-font-family: Verdana; mso-bidi-font-family: Verdana;"><span style="mso-list: Ignore;">2.<span style="font: 7pt 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">最长路径匹配。例子：</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servletA</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url-pattern</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">为</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">/test/*</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，而</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servletB</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url-pattern</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">为</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">/test/a/*</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，此时访问</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"><a href="http://localhost/test/a"><span style="color: #108ac6;">http://localhost/test/a</span></a></span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">时，容器会选择路径最长的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">来匹配，也就是这里的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servletB</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">。</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;"></span></p>
<p class="MsoListParagraph" style="margin-left: 42pt; text-indent: -21pt; line-height: 150%; mso-char-indent-count: 0; mso-list: l1 level1 lfo1;"><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold; mso-fareast-font-family: Verdana; mso-bidi-font-family: Verdana;"><span style="mso-list: Ignore;">3.<span style="font: 7pt 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">扩展匹配，如果</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">最后一段包含扩展，容器将会根据扩展选择合适的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">。例子：</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servletA</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">的</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url-pattern</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">：</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">*.action</span></p>
<p class="MsoListParagraph" style="margin-left: 42pt; text-indent: -21pt; line-height: 150%; mso-char-indent-count: 0; mso-list: l1 level1 lfo1;"><strong><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-fareast-font-family: Verdana; mso-bidi-font-family: Verdana;"><span style="mso-list: Ignore;">4.<span style="font: 7pt 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">如果前面三条规则都没有找到一个</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，容器会根据</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">url</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">选择对应的请求资源。如果应用定义了一个</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">default servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">，则容器会将请求丢给</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">default servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-weight: bold;">（什么是</span><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif'; mso-bidi-font-weight: bold;">default servlet</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-weight: bold;">？后面会讲）</span><span style="color: black; font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold;">。</span><strong><span lang="EN-US" style="color: black; font-family: 'Verdana','sans-serif';"></span></strong></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="line-height: 150%;"><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"><span style="mso-spacerun: yes;">&nbsp;</span><span style="mso-tab-count: 1;">&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">根据这个规则表，就能很清楚的知道</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">servlet</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">的匹配过程，所以定义</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">servlet</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">的时候也要考虑</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">url-pattern</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">的写法，以免出错。</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"></span></p>
<p class="MsoNormal" style="line-height: 150%;"><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"><span style="mso-tab-count: 1;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">对于</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">filter</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">，不会像</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">servlet</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">那样只匹配一个</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">servlet</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">，因为</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">filter</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">的集合是一个链，所以只会有处理的顺序不同，而不会出现只选择一个</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">filter</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">。</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">Filter</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">的处理顺序和</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">filter-mapping</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">在</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">web.xml</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri;">中定义的顺序相同。</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif';"></span></p>
<h2 style="line-height: 150%;"><span style="font-size: small;"><span lang="EN-US" style="font-family: 'Verdana','sans-serif';">&nbsp;&nbsp;&nbsp; 二，url-pattern</span><span style="font-family: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Cambria;">详解</span><span lang="EN-US" style="font-family: 'Verdana','sans-serif'; mso-hansi-font-family: Cambria;"></span></span></h2>
<p class="MsoNormal" style="line-height: 150%;"><span lang="EN-US"><span style="mso-tab-count: 1;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">在</span><span lang="EN-US">web.xml</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">文件中，以下语法用于定义映射：</span></p>
<p class="MsoListParagraph" style="margin-left: 41.9pt; text-indent: -21pt; line-height: 150%; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;"><span lang="EN-US" style="font-family: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings;"><span style="mso-list: Ignore;">l<span style="font: 7pt 'Times New Roman';">&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">以</span><span lang="EN-US">&rdquo;/&rsquo;</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">开头和以</span><span lang="EN-US">&rdquo;/*&rdquo;</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">结尾的是用来做路径映射的。</span></p>
<p class="MsoListParagraph" style="margin-left: 41.9pt; text-indent: -21pt; line-height: 150%; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;"><span lang="EN-US" style="font-family: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings;"><span style="mso-list: Ignore;">l<span style="font: 7pt 'Times New Roman';">&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">以前缀</span><span lang="EN-US">&rdquo;*.&rdquo;</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">开头的是用来做扩展映射的。</span></p>
<p class="MsoListParagraph" style="margin-left: 41.9pt; text-indent: -21pt; line-height: 150%; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;"><span lang="EN-US" style="font-family: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings;"><span style="mso-list: Ignore;">l<span style="font: 7pt 'Times New Roman';">&nbsp; </span></span></span><span lang="EN-US">&ldquo;/&rdquo; </span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">是用来定义</span><span lang="EN-US">default servlet</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">映射的。</span></p>
<p class="MsoListParagraph" style="margin-left: 41.9pt; text-indent: -21pt; line-height: 150%; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;"><span lang="EN-US" style="font-family: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings;"><span style="mso-list: Ignore;">l<span style="font: 7pt 'Times New Roman';">&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">剩下的都是用来定义详细映射的。比如：</span><span lang="EN-US"> /aa/bb/cc.action</span></p>
<p class="MsoNormal" style="text-indent: 20.9pt; line-height: 150%;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">所以，为什么定义</span><span lang="EN-US">&rdquo;/*.action&rdquo;</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri;">这样一个看起来很正常的匹配会错？因为这个匹配即属于路径映射，也属于扩展映射，导致容器无法判断。</span></p>
          <br/>
          <span style="color:red;">
            <a href="http://lthu.javaeye.com/blog/213322#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 10 Jul 2008 10:00:24 +0800</pubDate>
        <link>http://lthu.javaeye.com/blog/213322</link>
        <guid>http://lthu.javaeye.com/blog/213322</guid>
      </item>
      <item>
        <title>Rose4J 模板引擎 2.0 开发完成，性能最大提升30倍</title>
        <author>lthu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lthu.javaeye.com">lthu</a>&nbsp;
          链接：<a href="http://lthu.javaeye.com/blog/162102" style="color:red;">http://lthu.javaeye.com/blog/162102</a>&nbsp;
          发表时间: 2008年02月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>最新内容请参考<a href="http://www.rose4j.cn/">www.rose4j.cn</a></p>
<p>经过几天的整理修正，现在Rose4J的WEB开发引擎2.0终于可以跟大家见面了，前台页面与后台java程序能完全分开，使用两端的工作都变得简单清晰，入门难度几乎为零，附件中是所需要的jar包，请下载试用。 <br /><br />下面我们来看看RoseForJ的模板的使用方法： <br /><br />一、WEB模板代码; <br /><br />HTML 代码 <br /><br />见附件（这里显示不了html代码，郁闷中） <br />从上面模板可以看出RoseForJ只有两个TAG（temp、include）和3个属性（for、id，remove），它也是一个标记语言，写法如下 ${变量表达式} 。 <br /><br />其中3个属性可用于html任何标签（如用于tr ，td等），for表示一个循环，for="${data:dataSet}" ,此时dataSet是一个集合对象或数组，data表示集合对象或数组对象中每一个成员。&nbsp;<br />&nbsp;</p>
<pre name="code" class="html">&lt;ul&gt;
	&lt;li j:for="${data:dataSet}"&gt;
		&lt;span j:id='${data.getName()}' id="showname"&gt;这里显示name&lt;/span&gt;
		&lt;span j:for="${xxx:xxSet}"&gt;
			
			&lt;span j:id='${data.getId()}' id="showid"&gt;这里显示nameID&lt;/span&gt;
			&lt;j:temp j:id='${xxx.getName()}'&gt;这里显示name&lt;/j:temp&gt;
			&lt;img src="http://localhost/roseforj/listImg.do?id=${xxx.getId()}&amp;name=testname" width="200" height="200"/&gt;
			xxx.id=${xxx.getId()} 
		&lt;/span&gt;
	&lt;/li&gt;
&lt;/ul&gt;</pre>
<p>&nbsp; 用法如上，如还有不懂的地方可以参考之前说明，2.0在性能上和非常大的提升，比纯jsp还要快。<br /></p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lthu.javaeye.com/blog/162102#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 13 Feb 2008 18:22:19 +0800</pubDate>
        <link>http://lthu.javaeye.com/blog/162102</link>
        <guid>http://lthu.javaeye.com/blog/162102</guid>
      </item>
      <item>
        <title>PowerDesigner Name/Code自动调整 </title>
        <author>lthu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lthu.javaeye.com">lthu</a>&nbsp;
          链接：<a href="http://lthu.javaeye.com/blog/159214" style="color:red;">http://lthu.javaeye.com/blog/159214</a>&nbsp;
          发表时间: 2008年01月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2><a href="http://www.cnblogs.com/coolstr/articles/215482.html" id="viewpost1_TitleUrl">PowerDesigner Name/Code自动调整 </a></h2><p>大家都清楚在用PowerDesigner的时候,当你输入Name的时候Code是会自动帮你按照Name的内容填上的.<br />这个功能虽然好用,但是我需要在Name这一项加上一个中文的注释,这个时候怎么办呢?<br />下面两个例子,相信对你相当有用.<br />Examples</p><p>&middot; Script 1: <br /><span style="color: #ff0000">.set_value(_First, true, new) <br />.foreach_part(%Name%, &quot;'#'&quot;) <br />.if (%_First%) <br />.delete(%CurrentPart%) <br />.set_value(_First, false, update) <br />.else <br />%CurrentPart% <br />.endif <br />.next</span><br />这个例子是把Name内容的#号后边的内容当作Code.<br />如:在Name列输入&nbsp;&nbsp;&nbsp;<strong> 用户名#user_name</strong>&nbsp; 则在Code列自动会变成&nbsp;&nbsp; <strong>user_name<br /></strong><br />&middot; Script 2: <br /><span style="color: #ff0000"><span style="color: #ff0000">.set_value(_First, true, new) <br />.foreach_part(%Name%, &quot;'#'&quot;) <br />.if (%_First%) <br />%CurrentPart% <br />.set_value(_First, false, update) <br />.endif <br />.next</span></span><br />这个例子是把Name内容的#号前边的内容当作Code.<br />如:在Name列输入&nbsp;&nbsp;&nbsp; <strong>user_name#用户名</strong>&nbsp; 则在Code列自动会变成&nbsp;&nbsp; <strong>user_name</strong><br /><br />具体操作方法是:<br />1、打开powerDesigner菜单的Tools-&gt;Model Options....-&gt;Naming Convention<br />2、选中Name,并勾选Enable name/code conversions.<br />3、选择Name To Code,把上面任意一个例子的代码（红色部分）贴到conversion script内容框中即可。<br /><br /><span style="color: #008000">注：用这个script的时候，必须先设置，才会转换的。<br />如果你已经设计好了，再设置是不会对之前的东西改变的。</span></p>
          <br/>
          <span style="color:red;">
            <a href="http://lthu.javaeye.com/blog/159214#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 24 Jan 2008 23:18:59 +0800</pubDate>
        <link>http://lthu.javaeye.com/blog/159214</link>
        <guid>http://lthu.javaeye.com/blog/159214</guid>
      </item>
      <item>
        <title>JDBC中处理存储过程的结果集的通用流程 </title>
        <author>lthu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lthu.javaeye.com">lthu</a>&nbsp;
          链接：<a href="http://lthu.javaeye.com/blog/147601" style="color:red;">http://lthu.javaeye.com/blog/147601</a>&nbsp;
          发表时间: 2007年12月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>转载：<font face="Courier New" style="BACKGROUND-COLOR: #fafafa"><a href="http://allenj2ee.javaeye.com/blog/134459">http://allenj2ee.javaeye.com/blog/134459</a></font></span></span></li>
    <li class="alt"><span><span></span></span></li>
    <li class="alt"><span><span>oracle&nbsp;对于高级特性总是与众不同(我极力讨厌这一点,如果使用它的产品就要对这种产品 &nbsp;&nbsp;</span></span> </li>
    <li class=""><span>进行特定的编程,这也是我从不看好weblogic之类的平台的原因),大对象存取一要定用它自己 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>的LOB对象,所幸我还能通过LONG&nbsp;RAW来代替.以便能使程序不需要特定的编码.但对于存储过程 &nbsp;&nbsp;</span> </li>
    <li class=""><span>(我是说返回结果集的存储过程),我还没有什么方法能用一个通用的程序来处理ORACLE.太多的 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>教材或文章在讲存储过程的调用只是不负责任地简单执行一些涵数或无结果返回的存储过程, &nbsp;&nbsp;</span> </li>
    <li class=""><span>使大多数读者根本不知道到底如何调用存储过程的结果集.而在Spring中,根本就没有真正完全 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>地介绍对存储过程的结果集的处理,更别说象oracle这种</span><span class="string">&quot;特别&quot;</span><span>的存储过程的结果集处理. &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>先来简单看一下我们如何在JDBC中处理存储过程的结果集的通用流程: &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="number">1</span><span>.获取CallableStatement语句: &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>CallableStatement&nbsp;cs&nbsp;=&nbsp;conn.prepareCall(</span><span class="string">&quot;{call&nbsp;spName(?,?,?)}&quot;</span><span>); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="number">2</span><span>.传入输入参数和注册输出参数 &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>cs.setXXX(index,value);</span><span class="comment">//输入参数 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>cs.registerOutParameter(index,type);</span><span class="comment">//输出参数 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="number">3</span><span>.执行存储过程: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>cs.execute(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>对于一个存诸过程,如果返回的结果是我们预先知道的,那么可以根据存储过程定义的顺序来进行 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>处理(事实上一般不会这样),但对于复杂的多结果集的处理,如何定义一个通用的流程? &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>我们先看一下JDBC本身能为我们提供什么? &nbsp;&nbsp;</span> </li>
    <li class=""><span>一个存储过程执行后返回的是</span><span class="keyword">boolean</span><span>型: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">boolean</span><span>&nbsp;flag&nbsp;=&nbsp;callableStatement.execute(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>如果flag为</span><span class="keyword">true</span><span>,那么说明返回了一个结果集(ResultSet)类型,你可以用getResultSet()得到当前行所在 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>的结果,而如果返回为flase,说明什么呢? &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>如果你不进行处理,什么也不能说明,只能说明当前指针不是ResultSet,有可能是更新计数(updateCount) &nbsp;&nbsp;</span> </li>
    <li class=""><span>也可能什么也没有反因. &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>那么如果当前指针为flase时如何处理?我们应该先getUpdateCount();如果返回-</span><span class="number">1</span><span>,既不是结果集,又 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>不是更新计数了.说明没的返回了.而如果getUpdateCount()返回</span><span class="number">0</span><span>或大于</span><span class="number">0</span><span>,则说明当前指针是更新计数( &nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="number">0</span><span>的时候有可能是DDL指令).无论是返回结果集或是更新计数,那么则可能还继续有其它返回.只有在当前 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>指指针getResultSet()==</span><span class="keyword">null</span><span>&nbsp;&amp;&amp;&nbsp;getUpdateCount()&nbsp;==&nbsp;-</span><span class="number">1</span><span>才说明没有再多的返回. &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>存储过程的返回和ResultSet类似,每次处理的返回结果相当于是ResultSet的Row,只不过存储过程的Row &nbsp;&nbsp;</span> </li>
    <li class=""><span>最先在第一行而不是象ResultSet要先next才到第一行,存储过程向下移动一行用getMoreResults(),相 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>当于ResultSet的next().同样它返回</span><span class="keyword">boolean</span><span>和上面的flag一样,只是说明当前行是不是ResultSet,如果是 &nbsp;&nbsp;</span> </li>
    <li class=""><span>flase,你还是要判断是不是updateCount,在每一行,都要先同时判断是否为ResultSet还是UpdateCount,如 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>果是其中一种则要继续getMoreResults(),当不是ResultSet也不是updateCount时,说明没有返回结果了, &nbsp;&nbsp;</span> </li>
    <li class=""><span>这时再获取输出参数. &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>看明白了吗? &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>那我们就根据上面的规则来写一个通用的流程吧: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>首先,我们要确定什么时候没说结果集了: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">if</span><span>(cs.getResultSet()&nbsp;==&nbsp;</span><span class="keyword">null</span><span>&nbsp;&amp;&amp;&nbsp;cs.getUpdateCount()&nbsp;==&nbsp;-</span><span class="number">1</span><span>) &nbsp;&nbsp;</span> </li>
    <li class=""><span>现在我们做一个循环: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>ResultSet&nbsp;rs&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">int</span><span>&nbsp;updateCount&nbsp;=&nbsp;-</span><span class="number">1</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>flag&nbsp;=&nbsp;cs.execute(); &nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">do</span><span>{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;updateCount&nbsp;=&nbsp;cs.getUpdateCount(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(updateCount&nbsp;!=&nbsp;-</span><span class="number">1</span><span>){</span><span class="comment">//说明当前行是一个更新计数 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//处理. </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cs.getMoreResults(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">continue</span><span>;</span><span class="comment">//已经是更新计数了,处理完成后应该移动到下一行 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//不再判断是否是ResultSet </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;rs&nbsp;=&nbsp;cs.getResultSet(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(rs&nbsp;!=&nbsp;</span><span class="keyword">null</span><span>){</span><span class="comment">//如果到了这里,说明updateCount&nbsp;==&nbsp;-1 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//处理rs </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cs.getMoreResults(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">continue</span><span>; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//是结果集,处理完成后应该移动到下一行 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="comment">//如果到了这里,说明updateCount&nbsp;==&nbsp;-1&nbsp;&amp;&amp;&nbsp;rs&nbsp;==&nbsp;null,什么也没的了 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>}</span><span class="keyword">while</span><span>(!(updateCount&nbsp;==&nbsp;-</span><span class="number">1</span><span>&nbsp;&amp;&amp;&nbsp;rs&nbsp;==&nbsp;</span><span class="keyword">null</span><span>)); &nbsp;&nbsp;</span> </li>
    <li class=""><span>cs.getXXX(</span><span class="keyword">int</span><span>);</span><span class="comment">//获取输出参数 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>以上是对于通用的存储过程返回的结果集的处理,而oracle,它不能返回结果集,只能在输出参数中 &nbsp;&nbsp;</span> </li>
    <li class=""><span>返回一个cursor,所以通用的流程中你获取不到任何结果: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">package</span><span>&nbsp;PK_AREA_PUBLIC&nbsp;is &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>TYPE&nbsp;serarch_result&nbsp;IS&nbsp;REF&nbsp;CURSOR; &nbsp;&nbsp;</span> </li>
    <li class=""><span>PROCEDURE&nbsp;area_search(vTarget_in&nbsp;IN&nbsp;VARCHAR2&nbsp;,cur_result_out&nbsp;OUT&nbsp;serarch_result)&nbsp;; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>end&nbsp;PK_AREA_PUBLIC; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">package</span><span>&nbsp;body&nbsp;PK_AREA_PUBLIC&nbsp;is &nbsp;&nbsp;</span> </li>
    <li class=""><span>PROCEDURE&nbsp;area_search(vTarget_in&nbsp;IN&nbsp;VARCHAR2&nbsp;,cur_result_out&nbsp;OUT&nbsp;serarch_result) &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>IS &nbsp;&nbsp;</span> </li>
    <li class=""><span>sqlstr&nbsp;VARCHAR2(</span><span class="number">1000</span><span>); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>BEGIN &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sqlstr:='select&nbsp;.................................'; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OPEN&nbsp;cur_result_out&nbsp;FOR&nbsp;sqlstr&nbsp;USING&nbsp;vTarget_in; &nbsp;&nbsp;</span> </li>
    <li class=""><span>END&nbsp;area_search; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>end&nbsp;PK_AREA_PUBLIC; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>对于上面的例子,存储过程有一个输入参数,一个输出参数,我们要接受输出参数作为结果集处理.所 &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>以注册的时候应该注册为: &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>cs.registerOutParameter(</span><span class="number">2</span><span>,oracle.jdbc.OracleTypes.CURSOR);</span><span class="comment">//输出参数 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>这样在存储过程执行后,获取输出数造型为ResultSet就可以处理: &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>ResultSet&nbsp;rs&nbsp;=&nbsp;(ResultSet)cs.getObject(</span><span class="number">2</span><span>); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>如果有多个结果集就用多个输出参数. &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>明白了ORACLE的特殊性,我们再看看在spring中如果处理它的存储过程的结果集: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>spring在处理复杂对象的时候,大都采用回调的方法,要求程序员自己实现接口方法.也就是它提供了 &nbsp;&nbsp;</span> </li>
    <li class=""><span>程序运行时的参数,要求你自己对这些参数进行处理.对于JdbcTemplate,它在很多地方提供了ResultSet &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>参数供程序员处理.在Spring文档中提供了对于通用流程,也就是从存储过程执行结果中获取结果集的 &nbsp;&nbsp;</span> </li>
    <li class=""><span>例程: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>Map&nbsp;out&nbsp;=&nbsp;execute(</span><span class="keyword">new</span><span>&nbsp;HashMap()); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>其实它是默认实现了上面JDBC通用流程中对ResuleSet到Map的封装.而对于Oracle,我们就必须自己手 &nbsp;&nbsp;</span> </li>
    <li class=""><span>实现对输出参数中ResultSet的回调: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;SpringStoredProcedure &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">extends</span><span>&nbsp;StoredProcedure&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">public</span><span>&nbsp;ArrayList&nbsp;set&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;ArrayList(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="comment">//声明一个用于接收结果集的数据结构,其中的元素为row,用map存放 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">private</span><span>&nbsp;Map&nbsp;inParam;</span><span class="comment">//输入参数 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">private</span><span>&nbsp;RowMapper&nbsp;rm&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;RowMapper(){ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Object&nbsp;mapRow(ResultSet&nbsp;rs,</span><span class="keyword">int</span><span>&nbsp;rowNum)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;</span><span class="keyword">null</span><span>;</span><span class="comment">//不用从存储过程本身获取结果 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>}; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">private</span><span>&nbsp;RowMapperResultReader&nbsp;callback&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;RowMapperResultReader(rm&nbsp;){ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;processRow(ResultSet&nbsp;rs)&nbsp;</span><span class="comment">//回调处理 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;SQLException{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">int</span><span>&nbsp;count&nbsp;=&nbsp;rs.getMetaData().getColumnCount(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String[]&nbsp;header&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;String[count]; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;i=</span><span class="number">0</span><span>;i &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header[i]&nbsp;=&nbsp;rs.getMetaData().getColumnName(i+</span><span class="number">1</span><span>); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(rs.next()){ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HashMap&nbsp;row&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;HashMap(count+</span><span class="number">7</span><span>); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>(</span><span class="keyword">int</span><span>&nbsp;i=</span><span class="number">0</span><span>;i &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;row.put(header[i],rs.getString(i+</span><span class="number">1</span><span>)); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set.add(row); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class=""><span>};&nbsp;</span><span class="comment">//RowMapperResultReader作为输出参数的回调句柄 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span></span><span class="keyword">public</span><span>&nbsp;SpringStoredProcedure(DataSource&nbsp;ds,&nbsp;String&nbsp;SQL)&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;setDataSource(ds); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;setSql(SQL); &nbsp;&nbsp;</span> </li>
    <li class=""><span>} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setOutParameter(String&nbsp;column,</span><span class="keyword">int</span><span>&nbsp;type){ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;declareParameter(</span><span class="keyword">new</span><span>&nbsp;SqlOutParameter(column,&nbsp;type,callback)); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;</span><span class="comment">//利用回调句柄注册输出参数 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>} &nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setParameter(String&nbsp;column,</span><span class="keyword">int</span><span>&nbsp;type){ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;declareParameter(</span><span class="keyword">new</span><span>&nbsp;SqlParameter(column,&nbsp;type)); &nbsp;&nbsp;</span> </li>
    <li class=""><span>} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;SetInParam(Map&nbsp;inParam){ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.inParam&nbsp;=&nbsp;inParam; &nbsp;&nbsp;</span> </li>
    <li class=""><span>} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span></span><span class="keyword">public</span><span>&nbsp;Map&nbsp;execute()&nbsp;{ &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;compile(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;execute(</span><span class="keyword">this</span><span>.inParam); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>} &nbsp;&nbsp;</span> </li>
    <li class=""><span>} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>下面我们看一下调用过程: &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;DriverManagerDataSource&nbsp;ds&nbsp;=&nbsp;.......; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;SpringStoredProcedure&nbsp;sp&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;SpringStoredProcedure(ds,</span><span class="string">&quot;PK_AREA_PUBLIC.area_search&quot;</span><span>); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="comment">//注册参数类型,输入参数和输出参数同时注册,否则不能正确编译存储过程 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;sp.setParameter(</span><span class="string">&quot;vTarget_in&quot;</span><span>,java.sql.Types.VARCHAR); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;sp.setOutParameter(</span><span class="string">&quot;cur_result_out&quot;</span><span>,oracle.jdbc.OracleTypes.CURSOR); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;sp.compile(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp; &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;</span><span class="comment">//传入输入参数值 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;Map&nbsp;in&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;HashMap(); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;in.put(</span><span class="string">&quot;vTarget_in&quot;</span><span>,</span><span class="string">&quot;一个内容&quot;</span><span>); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;sp.SetInParam(in); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp; &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="comment">//执行存储过程 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;sp.execute(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;Map&nbsp;m&nbsp;=&nbsp;sp.set.get(</span><span class="number">0</span><span>);</span><span class="comment">//ReultSet的第一条记录 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="comment">//set定义为SpringStoredProcedure的属性用于接收回调时的数据 </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;</span><span class="comment">//如果有多个输出参数,应该在每个输出参数的回调方法中生成该输出 </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="comment">//参数对应的ArrayList,然后加到一个成员变量的数据结构中. </span><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;Iterator&nbsp;i&nbsp;=&nbsp;m.keySet().iterator(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(i.hasNext()){ &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;key&nbsp;=&nbsp;i.next().toString(); &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(key&nbsp;+&nbsp;</span><span class="string">&quot;=&gt;&quot;</span><span>&nbsp;+&nbsp;m.get(key)); &nbsp;&nbsp;</span> </li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;</span> </li>
    <li class=""><span>总之,上面的方法虽然解决了Spring中对Oracle存储过程的调用,但我极力不推荐这程复杂的处理。 &nbsp;&nbsp;</span> </li>
</ol>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://lthu.javaeye.com/blog/147601#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 11 Dec 2007 16:30:03 +0800</pubDate>
        <link>http://lthu.javaeye.com/blog/147601</link>
        <guid>http://lthu.javaeye.com/blog/147601</guid>
      </item>
      <item>
        <title>映射 SQL 和 Java 类型 </title>
        <author>lthu</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lthu.javaeye.com">lthu</a>&nbsp;
          链接：<a href="http://lthu.javaeye.com/blog/147275" style="color:red;">http://lthu.javaeye.com/blog/147275</a>&nbsp;
          发表时间: 2007年12月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <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>&nbsp;</p>
<h2>8.1 概述</h2>
<p>由于 SQL 数据类型和 Java 数据类型是不同的，因此需要某种机制在使用 Java 类型的应用程序和使用 SQL 类型的数据库之间来读写数据。</p>
<p>为此，JDBC 提供了 <code><font face="新宋体">getXXX</font></code> 和 <code><font face="新宋体">setXXX</font></code> 方法集、方法 <code><font face="新宋体">registerOutParameter</font></code> 和类 <code><font face="新宋体">Types</font></code>。</p>
<p>本章汇集了影响各种类和接口的数据类型的有关信息，并列出所有的对应关系表（这些表显示了 SQL 类型和 Java 类型之间的映射关系）以便于参考。</p>
<p>&nbsp;</p>
<h2>8.2 将 SQL 数据类型映射为 Java 类型</h2>
<p>不幸的是，不同数据库产品所支持的 SQL 类型之间有很大的不同。即使不同的数据库以相同的语义支持 SQL 类型，它们也可能用不同的名称。例如，绝大多数的主流数据库都支持一种表示大型二进制值的 SQL 类型，但 Oracle 把这种类型叫做 <code><font face="新宋体">LONG RAW</font></code>，Sybase 把它叫做 <code><font face="新宋体">IMAGE</font></code>，Informix 却把它叫做 <code><font face="新宋体">BYTE</font></code>，而 DB2 又把它叫做 <code><font face="新宋体">LONG VARCHAR FOR BIT DATA</font></code>。</p>
<p>幸运的是，JDBC 程序员通常并不需要自己去关心目标数据库所用的实际 SQL 类型的名称。大多数时候，JDBC 程序员将根据一些现有的数据库表来进行编程。他们无须关心用于创建这些表的确切 SQL 类型的名称。</p>
<p>JDBC 在 <code><font face="新宋体">java.sql.Types</font></code> 类中定义了一系列的常规 SQL 类型标识符。这些类型可用于表示那些最为常用的 SQL 类型。在用 JDBC API 编程时，程序员通常可以使用这些 JDBC 类型来引用一般的 SQL 类型，而无须关心目标数据库所用的确切 SQL 类型的名称。在下一节中将对这些 JDBC 类型进行仔细说明。</p>
<p>程序员用到 SQL 类型名称的主要地方是在用 SQL 的 <code><font face="新宋体">CREATE TABLE </font></code>语句创建新的数据库表时。这种情况下，程序员必须注意应该使用目标数据库所支持的 SQL 类型名称。如果需要知道各种 SQL 类型在某个特定的数据库中的行为的确切定义，我们建议查阅一下数据库文档。</p>
<p>如果想要编写一种可在各种数据库上创建表的可移植 JDBC 程序，用户主要有两个选择。第一个选择是：限制自己只使用那些被广为接受的 SQL 类型名称（例如 <code><font face="新宋体">INTEGER</font></code>、<code><font face="新宋体">NUMERIC</font></code> 或 <code><font face="新宋体">VARCHAR</font></code>）。这些类型有可能能适应所有的数据库。第二个选择是：用 <code><font face="新宋体">java.sql.DatabaseMetaData.getTypeInfo</font></code> 方法来找出给定的数据库实际上支持哪些 SQL 类型，然后选择与给定 JDBC 类型相匹配的特定于数据库的 SQL 类型名。</p>
<p>JDBC 定义了一个从 JDBC 数据库类型到 Java 类型的标准映射。例如，JDBC 的 <code><font face="新宋体">INTEGER</font></code> 类型通常映射为 Java 的 <code><font face="新宋体">int</font></code> 类型。这可支持简单的接口，将 JDBC 值读写为简单的 Java 类型。</p>
<p>Java 类型不必与 JDBC 类型完全形同；它们只须能够用足够的类型信息来代表 JDBC 类型，从而能正确地存储和取出参数和从 SQL 语句恢复结果就可以了。例如，Java <code><font face="新宋体">String</font></code> 对象可能并不能精确地与任何 JDBC <code><font face="新宋体">CHAR</font></code> 类型匹配，但它却可给出足够的类型信息来成功地表示 <code><font face="新宋体">CHAR</font></code>、 <code><font face="新宋体">VARCHAR</font></code> 或 <code><font face="新宋体">LONGVARCHAR</font></code> 类型。</p>
<p>&nbsp;</p>
<h2>8.3 JDBC 类型</h2>
<p>本节描述各种 JDBC 数据类型及其与标准 SQL 类型和 Java 类型的关联方式。</p>
<p>&nbsp;</p>
<h3>8.3.1 CHAR、 VARCHAR 和 LONGVARCHAR</h3>
<p>JDBC 类型 <code><font face="新宋体">CHAR</font></code>、<code><font face="新宋体">VARCHAR</font></code> 和 <code><font face="新宋体">LONGVARCHAR</font></code> 密切相关。<code><font face="新宋体">CHAR</font></code> 表示固定长度的小字符串，<code><font face="新宋体">VARCHAR</font></code> 表示长度可变的小字符串，而 <code><font face="新宋体">LONGVARCHAR</font></code> 表示长度可变的大字符串。</p>
<p>与 JDBC <code><font face="新宋体">CHAR</font></code> 对应的是 SQL <code><font face="新宋体">CHAR</font></code> 类型，其定义由 SQL-92 给出，且所有主要的数据库都支持它。它接受用于指定字符串最大长度的参数，例如 <code><font face="新宋体">CHAR(12)</font></code> 即定义了一个长度为 12 个字符的字符串。所有主要的数据库都支持长度达 254 个字符的 <code><font face="新宋体">CHAR</font></code>。</p>
<p>与 JDBC <code><font face="新宋体">VARCHAR</font></code> 对应的是 SQL <code><font face="新宋体">VARCHAR</font></code> 类型，其定义由 SQL-92 给出，且所有的主要数据库都支持它。它接受用于指定字符串最大长度的参数，例如 <code><font face="新宋体">VARCHAR(12)</font></code> 即定义了一个最大长度为 12 个字符的字符串。所有主要数据库都至少支持长度达 254 个字符的 <code><font face="新宋体">VARCHAR</font></code>。当把字符串的值赋给 <code><font face="新宋体">VARCHAR</font></code> 变量时，数据库就记住该字符串的长度，使用 <code><font face="新宋体">SELECT 时，它可以</font></code>返回准确的原始字符串。</p>
<p>不幸的是，对于 JDBC <code><font face="新宋体">LONGVARCHAR</font></code> 类型，目前并没有一致的 SQL 映射。所有主要数据库都支持某种类型的长度可变的大字符串，这种字符串支持高达十亿位字节的数据，但 SQL 类型名称却变化多样。</p>
<p>Java 程序员不必区分 <code><font face="新宋体">CHAR</font></code>、<code><font face="新宋体">VARCHAR</font></code> 和 <code><font face="新宋体">LONGVARCHAR</font></code> 这三种类型的 JDBC 字符串。它们都可表示为 Java <code><font face="新宋体">String</font></code>，并且在不知道所需要的确切数据类型时也可正确读写 SQL 语句。</p>
<p><code><font face="新宋体">CHAR</font></code>、<code><font face="新宋体">VARCHAR</font></code> 和 <code><font face="新宋体">LONGVARCHAR</font></code> 可映射为 <code><font face="新宋体">String</font></code> 或 <code><font face="新宋体">char[]</font></code>，但 <code><font face="新宋体">String</font></code> 更适合于一般用法。同时， <code><font face="新宋体">String</font></code> 类能使 <code><font face="新宋体">String</font></code> 和 <code><font face="新宋体">char[]</font></code> 之间的转换更为容易：它有一个用于将 <code><font face="新宋体">String</font></code> 对象转换为 <code><font face="新宋体">char[]</font></code> 的方法，还有一个将<code><font face="新宋体"> char[]</font></code> 转换为 <code><font face="新宋体">String</font></code> 对象的构造函数。</p>
<p>必须提及的一个问题是：如何处理类型为 <code><font face="新宋体">CHAR(n)</font></code> 的固定长度的 SQL 字符串。答案是 JDBC 驱动程序（或 DBMS）将用适当的空格来进行填补。因此，当从数据库中检索 <code><font face="新宋体">CHAR(n)</font></code> 域时，驱动程序将把它转换为长度为 <code><font face="新宋体">n</font></code> 的 Java <code><font face="新宋体">String</font></code> 对象，对象末尾可能含有一些填补空格。反之，当把 <code><font face="新宋体">String</font></code> 对象送到某个 <code><font face="新宋体">CHAR(n)</font></code> 域时，驱动程序和/或数据库将在字符串的末尾填上一些必要的空格，使字符串的长度达到 <code><font face="新宋体">n</font></code>。</p>
<p>方法 <code><font face="新宋体">ResultSet.getString</font></code> 用于分配和返回新的 <code><font face="新宋体">String</font></code> 对象。我们建议用它来从 <code><font face="新宋体">CHAR</font></code>、<code><font face="新宋体">VARCHAR</font></code> 和<code><font face="新宋体">LONGVARCHAR</font></code> 域中检索数据。它适用于检索普通的数据，但如果用 JDBC 类型 <code><font face="新宋体">LONGVARCHAR</font></code> 来储存多个兆字节的字符串时，用它进行检索将显得十分笨拙。为此，<code><font face="新宋体">ResultSet</font></code> 接口中有两个方法可供程序员将 <code><font face="新宋体">LONGVARCHAR</font></code> 值作为 Java 输入流进行检索，之后可从该流中以任意大小的块来读取数据。这两个方法是<code><font face="新宋体">：getAsciiStream</font></code> 和 <code><font face="新宋体">getUnicodeStream</font></code>，它们将把储存在 <code><font face="新宋体">LONGVARCHAR</font></code> 列的数据作为 Ascii 或 Unicode 字符流来传送。</p>
<p>&nbsp;</p>
<h3>8.3.2 BINARY、VARBINARY 和 LONGVARBINARY</h3>
<p>JDBC 类型 <code><font face="新宋体">BINARY</font></code>、<code><font face="新宋体">VARBINARY</font></code> 和 <code><font face="新宋体">LONGVARBINARY</font></code> 密切相关。<code><font face="新宋体">BINARY</font></code> 表示固定长度的小二进制值， <code><font face="新宋体">VARBINARY</font></code> 表示长度可变化的小二进制值，而 <code><font face="新宋体">LONGVARBINARY</font></code> 表示长度可变化的大二进制值。</p>
<p>不幸的是，这些不同 <code><font face="新宋体">BINARY</font></code> 类型的使用还未被标准化，因而在各种主要数据库提供的支持有很大的不同。</p>
<p>对应于 JDBC <code><font face="新宋体">BINARY</font></code> 类型的 SQL <code><font face="新宋体">BINARY</font></code> 类型，是一种非标准的 SQL 扩展，只在某些数据库上才实现。它接受用于指定二进制字节数的参数。例如，<code><font face="新宋体">BINARY(12)</font></code> 即定义了一个长度为 12 个字节的 binary 类型。通常，<code><font face="新宋体">BINARY </font></code>值被限定在 254 个字节以内。</p>
<p>对应于 JDBC <code><font face="新宋体">VARBINARY</font></code> 类型的 SQL <code><font face="新宋体">VARBINARY</font></code> 类型，是一种非标准的 SQL 扩展，只在某些数据库上才实现。它接受用于指定二进制字节最大数的参数。例如，<code><font face="新宋体">VARBINARY(12)</font></code> 即定义了一个长度最大可为 12 个字节的二进制类型。通常，<code><font face="新宋体">VARBINARY</font></code> 的值被限定在 254 个字节以内。当把二进制的值赋给 <code><font face="新宋体">VARBINARY</font></code> 变量时，数据库就记住这个所赋值的长度，调用 <code><font face="新宋体">SELECT</font></code> 时，它返回准确的原始值。</p>
<p>遗憾的是，目前还没有一致的 SQL 类型名称与 JDBC <code><font face="新宋体">LONGVARBINARY</font></code> 类型相对应。所有主要数据库都支持某种类型的长度可变的大二进制类型，它可支持高达十亿个字节的数据，但 SQL 类型名称却变化多样。</p>
<p>在 Java 中，<code><font face="新宋体">BINARY</font></code>、<code><font face="新宋体">VARBINARY</font></code> 和 <code><font face="新宋体">LONGVARBINARY</font></code> 都可用同一 <code><font face="新宋体">byte</font></code> 数组来表示。由于可在不知道所需的 确切 <code><font face="新宋体">BINARY</font></code> 数据类型的情况下正确地读写 SQL 语句，因此，Java 程序员无需区分它们。</p>
<p>检索 <code><font face="新宋体">BINARY</font></code> 和 <code><font face="新宋体">VARBINARY</font></code> 值时，我们建议使用 <code><font face="新宋体">ResultSet.getBytes</font></code>。然而，如果类型为 JDBC <code><font face="新宋体">LONGVARBINARY</font></code> 的某列储存的是几兆字节长度的字节数组，则建议用方法 <code><font face="新宋体">getBinaryStream</font></code> 来检索。与 <code><font face="新宋体">LONGVARCHAR</font></code> 的情形类似，该方法可以使 Java 程序员将 <code><font face="新宋体">LONGVARBINARY</font></code> 值作为 Java 输入流检索，然后可从该流中以更小的块来读取。</p>
<p>&nbsp;</p>
<h3>8.3.3 BIT</h3>
<p>JDBC 类型 <code><font face="新宋体">BIT</font></code> 代表一个位值，可为 0 或 1。</p>
<p>SQL-92 定义了 SQL <code><font face="新宋体">BIT</font></code> 类型。但与 JDBC <code><font face="新宋体">BIT</font></code> 类型不同，这种 SQL-92 BIT 类型带参数，用于定义固定长度的二进制字符串。幸运的是，SQL-92 也允许用简单的非参数化的 <code><font face="新宋体">BIT</font></code> 类型来代表单个的二进制数字。这种用法对应于 JDBC <code><font face="新宋体">BIT</font></code> 类型。不幸的是，SQL-92 <code><font face="新宋体">BIT</font></code> 类型只有在 &ldquo;完全&rdquo; SQL-92 中才要求，且目前只有一部份主流数据库支持它。因此，可移植的代码也许宁愿用 JDBC <code><font face="新宋体">SMALLINT</font></code> 类型，这种类型已得到广泛支持。</p>
<p>JDBC <code><font face="新宋体">BIT</font></code> 类型的 Java 映射的推荐类型是 Java 布尔型。</p>
<p>&nbsp;</p>
<h3>8.3.4 TINYINT</h3>
<p>JDBC 类型 <code><font face="新宋体">TINYINT</font></code> 代表一个 8 位无符号整数，其值在 0 到 255 之间。</p>
<p>对应的 SQL 类型 <code><font face="新宋体">TINYINT</font></code> 目前只有一部份的数据库支持它。因此，可移植的代码也许宁愿用 JDBC <code><font face="新宋体">SMALLINT</font></code> 类型，这种类型已得到广泛支持。</p>
<p>JDBC <code><font face="新宋体">TINYINT</font></code> 类型的 Java 映射的推荐类型是 Java <code><font face="新宋体">byte</font></code> 或 Java <code><font face="新宋体">short</font></code>。8 位的 Java <code><font face="新宋体">byte</font></code> 类型代表一个有符号的整数，其值在 -128 到 127 之间，因此对于大的 <code><font face="新宋体">TINYINT</font></code> 值它并非总合适，而 16 位的 Java <code><font face="新宋体">short</font></code> 类型却总能存储所有的 <code><font face="新宋体">TINYINT</font></code> 值。</p>
<p>&nbsp;</p>
<h3>8.3.5 SMALLINT</h3>
<p>JDBC 类型 <code><font face="新宋体">SMALLINT</font></code> 代表一个 16 位的有符号整数，其值在 -32768 和 32767 之间。</p>
<p>对应的 SQL 类型 <code><font face="新宋体">SMALLINT</font></code>，其定义由 SQL- 92 给出，并为所有主流数据库所支持。SQL-92 标准将 <code><font face="新宋体">SMALLINT</font></code> 的精度留给实现去决定。但事实上，所有的主流数据库都至少支持 16 位。</p>
<p>JDBC <code><font face="新宋体">SMALLINT</font></code> 类型的 Java 映射的推荐类型是 Java <code><font face="新宋体">short</font></code> 类型。</p>
<p>&nbsp;</p>
<h3>8.3.6 INTEGER</h3>
<p>JDBC 类型 <code><font face="新宋体">INTEGER</font></code> 代表一个 32 位的有符号整数，其值在 - 2147483648 和 2147483647 之间。</p>
<p>对应的 SQL 类型 <code><font face="新宋体">INTEGER</font></code>，其定义由 SQL- 92 给出，并为所有主流数据库所广为支持。SQL-92 标准将 <code><font face="新宋体">INTEGER</font></code> 的精度留给实现去决定。但事实上，所有的主流数据库都至少支持 32 位。</p>
<p><code><font face="新宋体">INTEGER</font></code> 类型 Java 映射的推荐类型是 Java <code><font face="新宋体">int</font></code> 类型。</p>
<p>&nbsp;</p>
<h3>8.3.7 BIGINT</h3>
<p>JDBC 类型 <code><font face="新宋体">BIGINT</font></code> 代表一个 64 位的有符号整数，其值在 -9223372036854775808 和 9223372036854775807 之间。</p>
<p>对应的 SQL 类型 <code><font face="新宋体">BIGINT</font></code> 是 SQL 的一个非标准扩展。事实上，目前还没有任何数据库实现 SQL <code><font face="新宋体">BIGINT</font></code> 类型。我们建议在可移植的代码中避免使用该类型。</p>
<p><code><font face="新宋体">BIGINT</font></code> 类型的 Java 映射的推荐类型是 Java long 类型。</p>
<p>&nbsp;</p>
<h3>8.3.8 REAL</h3>
<p>JDBC 类型 <code><font face="新宋体">REAL</font></code> 代表一个有 7 位尾数的&ldquo;单精度&rdquo;浮点数。</p>
<p>对应的 SQL 类型 <code><font face="新宋体">REAL</font></code>，其定义由 SQL- 92 给出。虽然未得到普遍支持，但在主流数据库中却已得到广泛支持。SQL-92 标准将 <code><font face="新宋体">REAL</font></code> 的精度留给实现去决定。但事实上，所有的支持 <code><font face="新宋体">REAL</font></code> 类型的主流数据库都支持至少 7 位数的尾数精度。</p>
<p><code><font face="新宋体">REAL</font></code> 类型的 Java 映射的推荐类型为 Java <code><font face="新宋体">float</font></code> 类型。</p>
<p>&nbsp;</p>
<h3>8.3.9 DOUBLE</h3>
<p>JDBC 类型 <code><font face="新宋体">DOUBLE</font></code> 代表一个有 15 位尾数的&ldquo;双精度&rdquo;浮点数。</p>
<p>对应的 SQL 类型是 <code><font face="新宋体">DOUBLE</font></code> <code><font face="新宋体">PRECISION</font></code>，其定义由 SQL- 92 给出，并为主流数据库所广为支持。SQL-92 标准将 <code><font face="新宋体">DOUBLE</font></code> <code><font face="新宋体">PRECISION</font></code> 的精度留给实现去决定。但事实上，所有支持 <code><font face="新宋体">DOUBLE</font></code> <code><font face="新宋体">PRECISION</font></code> 类型的主流数据库都支持至少 15 位数的尾数精度。</p>
<p><code><font face="新宋体">DOUBLE</font></code> 类型的 Java 映射的推荐类型为 Java <code><font face="新宋体">double</font></code> 类型。</p>
<p>&nbsp;</p>
<h3>8.3.10 FLOAT</h3>
<p>JDBC 类型 <code><font face="新宋体">FLOAT</font></code> 基本上与 JDBC 类型 <code><font face="新宋体">DOUBLE</font></code> 相同。我们同时提供了 <code><font face="新宋体">FLOAT</font></code> 和 <code><font face="新宋体">DOUBLE</font></code>，其目的是与以前的 API 实现一致。但这却有可能产生误导。<code><font face="新宋体">FLOAT</font></code> 代表一个有 15 位尾数的&ldquo;双精度&rdquo;浮点数。</p>
<p>对应的 SQL 类型 <code><font face="新宋体">FLOAT</font></code>，其定义由 SQL-92 给出。SQL-92 标准将 <code><font face="新宋体">FLOAT</font></code> 的精度留给实现去决定。但事实上，所有支持 <code><font face="新宋体">FLOAT</font></code> 类型的主流数据库都支持至少 15 位数的尾数精度。</p>
<p><code><font face="新宋体">FLOAT</font></code> 类型的 Java 映射的推荐类型为 Java <code><font face="新宋体">double</font></code> 类型。然而，由于 SQL <code><font face="新宋体">FLOAT</font></code> 和单精度的 Java <code><font face="新宋体">float</font></code>类型间可能产生混淆，因此建议 JDBC 程序员通常选用 JDBC <code><font face="新宋体">DOUBLE</font></code> 类型而不选用 <code><font face="新宋体">FLOAT</font></code>。</p>
<p>&nbsp;</p>
<h3>8.3.11 DECIMAL 和 NUMERIC</h3>
<p>JDBC 类型 <code><font face="新宋体">DECIMAL</font></code> 和 <code><font face="新宋体">NUMERIC</font></code> 两者非常相似。它们都表示固定精度的十进制值。</p>
<p>相应的 SQL 类型 <code><font face="新宋体">DECIMAL</font></code> 和 <code><font face="新宋体">NUMERIC</font></code>，其定义在 SQL-92 中给出，并得到广泛支持。这些 SQL 类型都带有精度和比例参数。精度是所支持的十进制数字的总位数，比例是小数点后的数字位数。比例必须永远小于或等于精度。例如，值 &quot;12.345&quot; 有 5 位精度和 3 位比例，而值 &quot;.11&quot; 有 2 位精度和 2 位比例。JDBC 要求所有 <code><font face="新宋体">DECIMAL</font></code> 和 <code><font face="新宋体">NUMERIC</font></code> 类型都必须支持至少 15 位的精度和比例。</p>
<p><code><font face="新宋体">DECIMAL</font></code> 和 <code><font face="新宋体">NUMERIC</font></code> 之间的唯一区别是 SQL-92 规范要求 <code><font face="新宋体">NUMERIC</font></code> 类型必须以确切指定的精度来表示，而对<code><font face="新宋体"> DECIMAL</font></code> 类型，它允许实现在创建该类型时所指定的精度以外再添加额外的精度。因此，创建为类型 <code><font face="新宋体">NUMERIC(12,4)</font></code> 的列将总是用 12 位数来表示，而创建为类型 <code><font face="新宋体">DECIMAL(12,4)</font></code> 的列则可用更大的位数来表示。</p>
<p><code><font face="新宋体">DECIMAL</font></code> 和 <code><font face="新宋体">NUMERIC</font></code> 类型的 Java 映射的推荐类型是<code><font face="新宋体"> java.math.BigDecimal</font></code>，该 Java 类型也用绝对精度来表示定点数。<code><font face="新宋体">java.math.BigDecimal</font></code> 类型提供了一些数学操作，可对 <code><font face="新宋体">BigDecimal</font></code> 类型与其它的 <code><font face="新宋体">BigDecimal</font></code> 类型、整数类型和浮点数类型进行加、减、乘、除的运算。</p>
<p>用于检索 <code><font face="新宋体">DECIMAL</font></code> 和 <code><font face="新宋体">NUMERIC</font></code> 值的推荐方法是 <code><font face="新宋体">ResultSet.getBigDecimal</font></code>。JDBC 还允许将这些 SQL 类型作为简单的 <code><font face="新宋体">Strings</font></code> 或 <code><font face="新宋体">char</font></code> 数组来访问。因此，Java 程序员可用 <code><font face="新宋体">getString</font></code> 来检索 <code><font face="新宋体">DECIMAL</font></code> 或 <code><font face="新宋体">NUMERIC</font></code> 结果。然而，这将使常见的用 <code><font face="新宋体">DECIMAL</font></code> 或 <code><font face="新宋体">NUMERIC</font></code> 来表示的货币值变得极为尴尬，因为它意味着应用程序编程人员必须对字符串进行数学运算。当然，也可将这些 SQL 类型作为 Java 数值型类型来检索。</p>
<p>&nbsp;</p>
<h3>8.3.12 DATE、TIME 和 TIMESTAMP</h3>
<p>有三种 JDBC 类型与时间有关： </p>
<ul>
    <p>&nbsp;</p>
    <li>JDBC <code><font face="新宋体">DATE</font></code> 类型表示一个由年、月、日组成的日期。对应的是 SQL <code><font face="新宋体">DATE </font></code>类型，其定义由 SQL-92 给出，但只有一部份主流数据库实现它。某些数据库提供了另外一些支持类似语义的 SQL 类型。<br />
    </li>
    <li>JDBC <code><font face="新宋体">TIME</font></code> 类型表示一个由小时、分钟和秒组成的时间。对应的是 SQL <code><font face="新宋体">TIME</font></code> 类型，其定义由 SQL-92 给出，但只有一部份主流数据库实现它。与 <code><font face="新宋体">DATE</font></code> 一样，某些数据库提供了另外一些支持类似语义的 SQL 类型。<br />
    </li>
    <li>JDBC <code><font face="新宋体">TIMESTAMP</font></code> 类型表示 <code><font face="新宋体">DATE</font></code> 加上 <code><font face="新宋体">TIME</font></code>，外加一个纳秒域。对应的 <code><font face="新宋体">TIMESTAMP </font></code>类型，其定义由 SQL-92 给出，但只有少数几个数据库实现它。<br />
    </li>
</ul>
<p>&nbsp;</p>
<p>由于标准的 Java 类 <code><font face="新宋体">java.util.Date</font></code> 并不与这三个 JDBC 日期&mdash;时间类型完全匹配（它含有<code><font face="新宋体"> DATE</font></code> 和 <code><font face="新宋体">TIME</font></code> 的信息但不含纳秒信息），因此 JDBC 定义了三个 <code><font face="新宋体">java.util.Date</font></code> 的子类与 SQL 类型对应。它们是： </p>
<ul>
    <p>&nbsp;</p>
    <li><code><font face="新宋体">java.sql.Date</font></code>，对应于 SQL <code><font face="新宋体">DATE</font></code> 信息。<code><font face="新宋体">java.util.Date</font></code> 基本类中的小时、分钟和秒都设为 0。<br />
    </li>
    <li><code><font face="新宋体">java.sql.Time</font></code>，对应于 SQL <code><font face="新宋体">TIME</font></code> 信息。<code><font face="新宋体">java.util.Date</font></code> 基本类中的年、月、日域设为 1970 年 1 月 1 日。这是 Java 纪元的&ldquo;零&rdquo;日期。<br />
    </li>
    <li><code><font face="新宋体">java.sql.Timestamp</font></code>，对应于 SQL <code><font face="新宋体">TIMESTAMP</font></code> 信息。该类扩展了 <code><font face="新宋体">java.util.Date</font></code>，添加了纳秒域。<br />
    </li>
</ul>
<p>&nbsp;</p>
<p>所有这三个与时间有关的 JDBC 类都是 <code><font face="新宋体">java.util.Date</font></code> 的子类，因此它们可用在任何可以使用 <code><font face="新宋体">java.util.Date</font></code> 的地方。例如，国际化 (internationalization) 方法将 <code><font face="新宋体">java.util.Date</font></code> 对象用作变量，因此可将这三个与时间有关的 JDBC 类中任何一个的实例作为参数传给国际化方法。</p>
<p>JDBC <code><font face="新宋体">Timestamp</font></code> 对象除了具有其父类的日期和时间成份外，还有一个独立的纳秒组件。如果将 <code><font face="新宋体">java.sql.Timestamp</font></code> 对象用于需要 <code><font face="新宋体">java.util.Date</font></code> 对象的地方，则纳秒组件将丢失。但由于是以毫秒的精度来储存 j<code><font face="新宋体">ava.util.Date</font></code> 对象的，因此将 <code><font face="新宋体">java.sql.Timestamp</font></code> 对象转换为 <code><font face="新宋体">java.util.Date</font></code> 对象时可以保持这样的精度。这可通过将纳秒组件中的纳秒转换为毫秒（用纳秒数除以 1,000,000）并将之添到 <code><font face="新宋体">java.util.Date</font></code> 对象中来实现。转换中可能丢失高达 999,999 纳秒，但所产生的 <code><font face="新宋体">java.util.Date</font></code> 对象将可精确到毫秒以内。</p>
<p>下述代码段将 <code><font face="新宋体">java.sql.Timestamp</font></code> 对象转换为精度达到毫秒量级的 <code><font face="新宋体">java.util.Date</font></code> 对象： </p>
<pre>    Timestamp t = new Timestamp(100, 0, 1, 15, 45, 29, 987245732);
    java.util.Date d;
    d = new java.util.Date(t.getTime() + (t.getNanos() / 1000000));
</pre>
<h2>8.4 映射示例</h2>
<p>任何情况下，当 Java 程序要从数据库中检索数据时，必须存在某种形式的映射和数据转换。大多数时候， JDBC 程序员将在知道其目标数据库机制的情况下进行编程。例如，他们将知道数据库含有哪些表、表中每一列的数据类型。因此，他们可使用 <code><font face="新宋体">ResultSet</font></code>、 <code><font face="新宋体">PreparedStatement</font></code>和 <code><font face="新宋体">CallableStatement</font></code> 接口中那些与类型有关的存取方法。本节给出三个示例，描述各种情形中所要求的数据映射和转换。</p>
<p>&nbsp;</p>
<h3>8.4.1 简单的 SQL 语句</h3>
<p>在最常见的情形中，用户将执行简单的 SQL 语句，然后取回含有结果的 <code><font face="新宋体">ResultSet</font></code> 对象。由数据库返回并存放在 <code><font face="新宋体">ResultSet</font></code> 列的值，其类型为 JDBC 数据类型。调用 <code><font face="新宋体">ResultSet.getXXX</font></code> 方法将把该值检索为 Java 数据类型。例如，如果某个 <code><font face="新宋体">ResultSet</font></code> 列含有一个 JDBC <code><font face="新宋体">FLOAT</font></code> 值，则方法 <code><font face="新宋体">getDouble</font></code> 将把它检索为 Java <code><font face="新宋体">double</font></code> 类型。<a href="http://kummy.itpub.net/mapping.doc.html#1006739">8.6.6</a> 节所示的表显示了哪些<code><font face="新宋体"> getXXX</font></code> 方法可检索哪些 JDBC 类型（如果用户不知道某个 <code><font face="新宋体">ResultSet</font></code> 列的类型，可通过调用 <code><font face="新宋体">ResultSet.getMetaData </font></code>方法来获得有关信息，然后再调用 <code><font face="新宋体">ResultSetMetaData</font></code> 的 <code><font face="新宋体">getColumnType</font></code> 或 <code><font face="新宋体">getColumnTypeName</font></code> 方法）。以下代码段示范了如何获得结果中各列的类型名称： </p>
<pre>    String query = &quot;select * from Table1&quot;;
    ResultSet rs = stmt.executeQuery(query);
    ResultSetMetaData rsmd = rs.getMetaData();
    int columnCount = rsmd.getColumnCount();
    for (int i = 1; i &lt;= columnCount; i++)  {
      String s = rsmd.getColumnTypeName(i);
      System.out.println (&quot;Column &quot; + i + &quot; is type &quot; + s);
    }
</pre>
<a name="1008288">
<h3><font color="#000000">8.4.2 带 IN 参数的 SQL 语句</font></h3>
<p><font color="#000000">在另一个可能的情况中，用户将发送带输入参数的 SQL 语句。这种情况下，用户通过调用 <code><font face="新宋体">PreparedStatement.setXXX</font></code> 方法为每个输入参数赋值。例如， <code><font face="新宋体">PreparedStatement.setLong(1, 2345678)</font></code> 将把值 <code><font face="新宋体">2345678</font></code> 作为 Java <code><font face="新宋体">的 long</font></code> 类型赋给第一个参数。为了将 <code><font face="新宋体">2345678</font></code> 到数据库中，驱动程序将把它转换为 JDBC <code><font face="新宋体">BIGINT</font></code>。驱动程序将把哪种 JDBC 类型送到数据库中是由 Java 类型到 JDBC 类型的标准映射所决定的，如 </font></p>
<p><font color="#000000"></font></p>
<h3><font color="#000000">8.4.3 带 OUT 参数的 SQL 语句</font></h3>
<p><font color="#000000">还有一个情况是，用户要调用已存储过程，将值赋给其 INOUT 参数，从结果中检索值，然后从参数中检索值。这种情形极为少见且相当复杂，但它却不失为映射和数据转换的好范例。</font></p>
<p><font color="#000000">这种情况下，首先要做的是用 <code><font face="新宋体">PreparedStatement.setXXX</font></code> 方法对 INOUT 参数赋值。此外，由于这些参数同时也用于输出，因此程序员必须为每个参数注册 JDBC 类型，该类型是数据库所要返回给该参数的值的 JDBC 类型。这可用 <code><font face="新宋体">CallableStatement.registerOutParameter</font></code> 方法来完成，后者接受在类 <code><font face="新宋体">Types</font></code> 中所定义的 JDBC 类型作为其变量。程序员可以用 <code><font face="新宋体">ResultSet.getXXX</font></code> 方法系列来检索返回给<code><font face="新宋体">ResultSet</font></code> 对象的结果，用 <code><font face="新宋体">CallableStatement.getXXX</font></code> 方法系列来检索存放在输出参数中的值。</font></p>
<p><font color="#000000">用于 <code><font face="新宋体">ResultSet</font></code>.<code><font face="新宋体">getXXX</font></code> 方法的 <code><font face="新宋体">XXX</font></code> 类型在某些情况下非常灵活。</font></p>
<p>用于 <code><font face="新宋体">CallableStatement</font></code>.<code><font face="新宋体">getXXX</font></code> 方法的<code><font face="新宋体"> XXX</font></code> 类型必须映射为那个参数所注册的 JDBC 类型。例如，如果数据库应返回类型为 <code><font face="新宋体">JDBC</font></code> <code><font face="新宋体">REAL</font></code> 的输出值，则该参数应被注册为 <code><font face="新宋体">java.sql.Types.REAL</font></code>。因此，要检索该 <code><font face="新宋体">JDBC</font></code> <code><font face="新宋体">REAL</font></code> 值，必须调用 <code><font face="新宋体">CallableStatement.getFloat</font></code> 方法（从 JDBC 类型到 Java 类型的映射在 <a href="http://kummy.itpub.net/mapping.doc.html#1004864">8.6.1</a> 节中的表中给出）。方法 <code><font face="新宋体">getFloat</font></code> 先把储存在输出参数中的值从 JDBC <code><font face="新宋体">REAL</font></code> 类型转换为 Java <code><font face="新宋体">float</font></code> 类型，然后将它返回。为了适应各种数据库和使应用程序具有更高的可移植性，建议先检索 <code><font face="新宋体">ResultSet</font></code> 对象中的值，再检索输出参数中的值。</p>
<p>下述代码示范的是调用名为 <code><font face="新宋体">getTestData</font></code> 的已存储过程。它有两个参数，且都是 INOUT 参数。首先， <code><font face="新宋体">Connection</font></code> 对象 <code><font face="新宋体">con</font></code> 将创建 <code><font face="新宋体">CallableStatement</font></code> 对象 <code><font face="新宋体">cstmt</font></code>。然后，方法 <code><font face="新宋体">setByte</font></code> 把第一个参数设置为 Java <code><font face="新宋体">byte</font></code> 类型，其值为 <code><font face="新宋体">25</font></code>。驱动程序将把 <code><font face="新宋体">25</font></code> 转换为 JDBC <code><font face="新宋体">TINYINT</font></code> 类型并将之送到数据库中。方法 <code><font face="新宋体">setBigDecimal</font></code> 用输入值 <code><font face="新宋体">83.75</font></code> 来设置第二个参数。驱动程序将把这个 <code><font face="新宋体">java.math.BigDecimal</font></code> 对象转换为 JDBC <code><font face="新宋体">NUMERIC</font></code> 值。接下来将这两个参数注册为 OUT 参数，第一个参数注册为 JDBC <code><font face="新宋体">TINYINT</font></code> 类型，第二个参数注册为小数点后面带两位数字的 JDBC <code><font face="新宋体">DECIMAL</font></code> 类型。执行 <code><font face="新宋体">cstmt</font></code> 后，就用 <code><font face="新宋体">ResultSet.getXXX</font></code> 方法将值从 <code><font face="新宋体">ResultSet</font></code> 对象中检索出来。方法 <code><font face="新宋体">getString</font></code> 将第一列中的值作为 Java <code><font face="新宋体">String</font></code> 对象获取， <code><font face="新宋体">getInt</font></code> 将第二列中的值作为 Java <code><font face="新宋体">int</font></code> 获取，<code><font face="新宋体">getInt</font></code> 将第三列中的值作为 Java <code><font face="新宋体">int</font></code> 获取。</p>
<p>之后， <code><font face="新宋体">CallableStatement.getXXX</font></code> 方法检索存放在输出参数中的值。方法 <code><font face="新宋体">getByte</font></code> 将 <code><font face="新宋体">JDBC</font></code> <code><font face="新宋体">TINYINT</font></code> 检索为 Java <code><font face="新宋体">byte</font></code>，<code><font face="新宋体">getBigDecimal</font></code> 将 <code><font face="新宋体">JDBC</font></code> <code><font face="新宋体">DECIMAL</font></code> 检索为小数点后面带有两位数字的 <code><font face="新宋体">java.math.BigDecimal</font></code> 对象。注意，当参数既是输入参数同时又是输出参数时，<code><font face="新宋体">setXXX</font></code> 方法所用的 Java 类型与 <code><font face="新宋体">getXXX</font></code> 方法所用的相同（正如 <code><font face="新宋体">setByte</font></code> 和 <code><font face="新宋体">getByte</font></code> 中一样）。<code><font face="新宋体">registerOutParameter</font></code> 方法将它注册成由 Java 类型映射来的 JDBC 类型（Java <code><font face="新宋体">byte</font></code> 类型映射为 JDBC <code><font face="新宋体">TINYINT</font></code>，如 <a href="http://kummy.itpub.net/mapping.doc.html#1004752">8.6.2</a> 节中的表所示）。</p>
<pre>    CallableStatement cstmt = con.prepareCall(
          &quot;{call getTestData(?, ?)}&quot;);
    cstmt.setByte(1, 25);
    cstmt.setBigDecimal(2, 83.75);
    // 将第一个参数注册为 JDBC TINYINT，第二个
    // 参数注册为小数点后面带有两位数字的 JDBC DECIMAL 类型
    cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
    cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 2);
    ResultSet rs = cstmt.executeUpdate();
    // 检索并打印结果中的值。
    while(rs.next()) {
      String name = rs.getString(1);
      int score = rs.getInt(2);
      int percentile = rs.getInt(3);
      System.out.print(&quot;name = &quot; + name + &quot;, score = &quot; + score + &quot;, &quot;
      System.out.println(&quot;percentile = &quot; + percentile);
    // 检索输出参数中的值 
    byte x = cstmt.getByte(1);
    java.math.BigDecimal n = cstmt.getBigDecimal(2, 2);
</pre>
<p>总之，<code><font face="新宋体">CallableStatement.getXXX</font></code> 和 <code><font face="新宋体">PreparedStatement.setXXX</font></code> 方法系列中的 <code><font face="新宋体">XXX</font></code> 是 Java 类型。对于 <code><font face="新宋体">setXXX</font></code> 方法，驱动程序先把 Java 类型转换为 JDBC 类型，再把它送到数据库中（使用 <a href="http://kummy.itpub.net/mapping.doc.html#1004752">8.6.2</a> 节中的表所示的标准映射）。对于 <code><font face="新宋体">getXXX</font></code> 方法， 驱动程序先把数据库返回的 JDBC 类型转换为 Java 类型（用 <a href="http://kummy.itpub.net/mapping.doc.html#1004864">8.6.1</a> 节表中所示的标准映射），再把它返回给 <code><font face="新宋体">getXXX</font></code> 方法。</p>
<p><code><font face="新宋体">registerOutParameter</font></code> 方法只接受 JDBC 类型的变量，而 <code><font face="新宋体">setObject</font></code> 方法却可接受 JDBC 类型的变量。 </p>
<p>注意，如果在可选的第三个变量的位置上提供了 JDBC 类型，则 <code><font face="新宋体">setObject</font></code> 方法将把参数值从 Java 类型显式地转换为所指定的 JDBC 类型。如果没有为<code><font face="新宋体"> setObject</font></code> 提供目标 JDBC 类型，则将把参数值转换为 Java 类型的标准映射 JDBC 类型（如 <a href="http://kummy.itpub.net/mapping.doc.html#1004752">8.6.2</a> 节的表中所示）。在将参数送到数据库中之前，驱动程序都要进行显式或隐式转换。</p>
<h2>8.5 动态数据存取</h2>
<p>大多数时候，用户要存取的结果和参数其数据类型在编译时是已知的。然而，有些应用程序（例如普通的浏览器或查询工具）在编译时对它们所要存取的数据库的机制并不知晓。因此，JDBC 除了支持静态数据类型存取外，还支持类型完全动态确定的数据存取。</p>
<p>有三种方法和一个常量可用于访问那些在编译时其数据类型尚属未知的值： </p>
<ul>
    <p>&nbsp;</p>
    <li><font face="新宋体"><code>ResultSet.getObject </code><br />
    </font></li>
    <li><font face="新宋体"><code>PreparedStatement.setObject </code><br />
    </font></li>
    <li><font face="新宋体"><code>CallableStatement.getObject </code><br />
    </font></li>
    <li><code><font face="新宋体">java.sql.Types.OTHER </font></code>（用作 <code><font face="新宋体">CallableStatement.registerOutParameter</font></code> 的一个变量） <br />
    </li>
</ul>
<p>&nbsp;</p>
<p>例如，如果应用程序想要接受多种类型作为其 <code><font face="新宋体">ResultSet</font></code> 对象中的结果，它可以使用 <code><font face="新宋体">ResultSet.getObject</font></code> 方法。</p>
<p><code><font face="新宋体">ResultSet.getObject</font></code> 和 <code><font face="新宋体">CallableStatement.getObject</font></code> 方法将值检索为 Java <code><font face="新宋体">Object</font></code>。由于 <code><font face="新宋体">Object</font></code> 是所有 Java 对象的基本类，因此可将任何 Java 类的实例检索为 <code><font face="新宋体">Object</font></code> 的实例。然而，以下 Java 类型是内置的&ldquo;基本&rdquo;类型，因此，它们不是类 <code><font face="新宋体">Object</font></code> 的实例： <code><font face="新宋体">boolean</font></code>、<code><font face="新宋体">char</font></code>、<code><font face="新宋体">byte</font></code>、<code><font face="新宋体">short</font></code>、<code><font face="新宋体">int</font></code>、<code><font face="新宋体">long</font></code>、 <code><font face="新宋体">float</font></code> 和 <code><font face="新宋体">double</font></code>。因此，不能用 <code><font face="新宋体">getObject</font></code> 方法来检索它们。然而，这些基本类型每种都有相应的可用作 wrapper 的类。这些类的实例是对象，这意味着可用 <code><font face="新宋体">ResultSet.getObject</font></code> 和 <code><font face="新宋体">CallableStatement.getObject</font></code> 方法来检索它们。<a href="http://kummy.itpub.net/mapping.doc.html#1004791">第 67 页中的表 8.6.3 </a>显示了从 JDBC 类型到 Java <code><font face="新宋体">Object</font></code> 类型的映射。该表与 JDBC 类型到 Java 类型的标准映射不同：在该表中，除了 JDBC <code><font face="新宋体">TINYINT</font></code> 和 JDBC <code><font face="新宋体">SMALLINT</font></code> 类型映射为 Java 类 <code><font face="新宋体">Integer</font></code> 之外，每一个基本的 Java 类型都被替换为它们的 wrapper 类。</p>
<p>方法 <code><font face="新宋体">getObject</font></code> 还可用于检索用户定义的 Java 类型。随着抽象数据类型（ADT）和其它用户定义的类型在某些数据库系统中的出现，一些提供者可能会发现用 <code><font face="新宋体">getObject</font></code> 来检索这些类型将更方便。</p>
<p>&nbsp;</p>
<h2>8.6 数据类型映射表</h2>
<p>本节含有以下表，它们是 JDBC 类型 和 Java 数据类型之间的映射关系表：&nbsp;&nbsp;</p>
<p><a href="http://kummy.itpub.net/mapping.doc.html#1004864">8.6.1 节</a> &mdash; 从 JDBC 类型映射到 Java 类型&nbsp;&nbsp;</p>
<p><a href="http://kummy.itpub.net/mapping.doc.html#1004752">8.6.2 节</a> &mdash; 从 Java 类型映射到 JDBC 类型&nbsp;&nbsp;</p>
<p><a href="http://kummy.itpub.net/mapping.doc.html#1004791">8.6.3 节</a> ─ 从 JDBC 类型映射到 Java <code><font face="新宋体">Object</font></code> 类型&nbsp;&nbsp;</p>
<p><a href="http://kummy.itpub.net/mapping.doc.html#1004830">8.6.4 节 </a>─ 从 Java <code><font face="新宋体">Object</font></code> 类型映射到 JDBC 类型&nbsp;&nbsp;</p>
<p><a href="http://kummy.itpub.net/mapping.doc.html#1004845">8.6.5 节</a> ─ 由 <code><font face="新宋体">setObject</font></code> 所进行的转换 </p>
<p>&nbsp;<a href="http://kummy.itpub.net/mapping.doc.html#1006739">8.6.6 节 </a>&mdash; 由 <code><font face="新宋体">ResultSet.getXXX</font></code> 方法所检索的 JDBC 类型 </p>
<p>&nbsp;</p>
<h3>8.6.1 从 JDBC 类型映射到 Java 类型</h3>
<table border="3">
    <tbody>
        <tr>
            <th valign="top"><strong>JDBC 类型 </strong></th>
            <th valign="top"><strong>Java 类型 </strong></th>
        </tr>
        <tr>
            <td><code><font face="新宋体">CHAR </font></code></td>
            <td><code><font face="新宋体">String </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">VARCHAR </font></code></td>
            <td><code><font face="新宋体">String </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">LONGVARCHAR </font></code></td>
            <td><code><font face="新宋体">String </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">NUMERIC </font></code></td>
            <td><code><font face="新宋体">java.math.BigDecimal </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">DECIMAL </font></code></td>
            <td><code><font face="新宋体">java.math.BigDecimal </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">BIT </font></code></td>
            <td><code><font face="新宋体">boolean </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">TINYINT </font></code></td>
            <td><code><font face="新宋体">byte </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">SMALLINT </font></code></td>
            <td><code><font face="新宋体">short </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">INTEGER </font></code></td>
            <td><code><font face="新宋体">int </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">BIGINT </font></code></td>
            <td><code><font face="新宋体">long </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">REAL </font></code></td>
            <td><code><font face="新宋体">float </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">FLOAT </font></code></td>
            <td><code><font face="新宋体">double </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">DOUBLE </font></code></td>
            <td><code><font face="新宋体">double </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">BINARY </font></code></td>
            <td><code><font face="新宋体">byte[] </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">VARBINARY </font></code></td>
            <td><code><font face="新宋体">byte[] </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">LONGVARBINARY </font></code></td>
            <td><code><font face="新宋体">byte[] </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">DATE </font></code></td>
            <td><code><font face="新宋体">java.sql.Date </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">TIME </font></code></td>
            <td><code><font face="新宋体">java.sql.Time </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">TIMESTAMP </font></code></td>
            <td><code><font face="新宋体">java.sql.Timestamp </font></code></td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<h3>8.6.2 从 Java 类型映射到 JDBC 类型</h3>
<p>该表显示的是表 <a href="http://kummy.itpub.net/mapping.doc.html#1004864">8.6.1</a> 的反映射：Java 类型到 JDBC 类型的映射。</p>
<table border="3">
    <tbody>
        <tr>
            <th valign="top"><strong>Java 类型 </strong></th>
            <th valign="top"><strong>JDBC 类型 </strong></th>
        </tr>
        <tr>
            <td><code><font face="新宋体">String </font></code></td>
            <td><code><font face="新宋体">VARCHAR 或 LONGVARCHAR </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">java.math.BigDecimal </font></code></td>
            <td><code><font face="新宋体">NUMERIC </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">boolean </font></code></td>
            <td><code><font face="新宋体">BIT </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">byte </font></code></td>
            <td><code><font face="新宋体">TINYINT </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">short </font></code></td>
            <td><code><font face="新宋体">SMALLINT </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">int </font></code></td>
            <td><code><font face="新宋体">INTEGER </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">long </font></code></td>
            <td><code><font face="新宋体">BIGINT </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">float </font></code></td>
            <td><code><font face="新宋体">REAL </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">double </font></code></td>
            <td><code><font face="新宋体">DOUBLE </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">byte[] </font></code></td>
            <td><code><font face="新宋体">VARBINARY 或 LONGVARBINARY </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">java.sql.Date </font></code></td>
            <td><code><font face="新宋体">DATE </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">java.sql.Time </font></code></td>
            <td><code><font face="新宋体">TIME </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">java.sql.Timestamp </font></code></td>
            <td><code><font face="新宋体">TIMESTAMP </font></code></td>
        </tr>
    </tbody>
</table>
<p>String 类型的映射通常是 <code><font face="新宋体">VARCHAR</font></code>，但如果所给的值超出了驱动程序对 <code><font face="新宋体">VARCHAR</font></code> 值所限定的极限，则将转换为 <code><font face="新宋体">LONGVARCHAR</font></code> 类型。对 <code><font face="新宋体">byte[]</font></code>、<code><font face="新宋体">VARBINARY</font></code> 及 <code><font face="新宋体">LONGVARBINARY</font></code> 值也一样。&nbsp;</p>
<p>&nbsp;</p>
<h3>8.6.3 从 JDBC 类型到 Java Object 类型的映射</h3>
<p>由于 Java 内置类型（例如 <code><font face="新宋体">boolean</font></code> 和 <code><font face="新宋体">int</font></code>）不是 <code><font face="新宋体">Object</font></code> 的子类型，因此对于 <code><font face="新宋体">getObject</font></code>/<code><font face="新宋体">setObject</font></code> 方法，从 JDBC 类型到 Java object 类型的映射稍有不同。此种映射如下表所示： </p>
<p>
<table border="3">
    <tbody>
        <tr>
            <th valign="top"><strong>JDBC 类型 </strong></th>
            <th valign="top"><strong>Java Object 类型 </strong></th>
        </tr>
        <tr>
            <td><code><font face="新宋体">CHAR </font></code></td>
            <td><code><font face="新宋体">String </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">VARCHAR </font></code></td>
            <td><code><font face="新宋体">String </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">LONGVARCHAR </font></code></td>
            <td><code><font face="新宋体">String </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">NUMERIC </font></code></td>
            <td><code><font face="新宋体">java.math.BigDecimal </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">DECIMAL </font></code></td>
            <td><code><font face="新宋体">java.math.BigDecimal </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">BIT </font></code></td>
            <td><code><font face="新宋体">Boolean </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">TINYINT </font></code></td>
            <td><code><font face="新宋体">Integer </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">SMALLINT </font></code></td>
            <td><code><font face="新宋体">Integer </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">INTEGER </font></code></td>
            <td><code><font face="新宋体">Integer </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">BIGINT </font></code></td>
            <td><code><font face="新宋体">Long </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">REAL </font></code></td>
            <td><code><font face="新宋体">Float </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">FLOAT </font></code></td>
            <td><code><font face="新宋体">Double </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">DOUBLE </font></code></td>
            <td><code><font face="新宋体">Double </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">BINARY </font></code></td>
            <td><code><font face="新宋体">byte[] </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">VARBINARY </font></code></td>
            <td><code><font face="新宋体">byte[] </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">LONGVARBINARY </font></code></td>
            <td><code><font face="新宋体">byte[] </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">DATE </font></code></td>
            <td><code><font face="新宋体">java.sql.Date </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">TIME </font></code></td>
            <td><code><font face="新宋体">java.sql.Time </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">TIMESTAMP </font></code></td>
            <td><code><font face="新宋体">java.sql.Timestamp </font></code></td>
        </tr>
    </tbody>
</table>
</p>
<h3>8.6.4 Java Object 类型映射到 JDBC 类型</h3>
<table border="3">
    <tbody>
        <tr>
            <th valign="top"><strong>Java Object 类型 </strong></th>
            <th valign="top"><strong>JDBC 类型 </strong></th>
        </tr>
        <tr>
            <td><code><font face="新宋体">String </font></code></td>
            <td><code><font face="新宋体">VARCHAR 或 LONGVARCHAR </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">java.math.BigDecimal </font></code></td>
            <td><code><font face="新宋体">NUMERIC </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">Boolean </font></code></td>
            <td><code><font face="新宋体">BIT </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">Integer </font></code></td>
            <td><code><font face="新宋体">INTEGER </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">Long </font></code></td>
            <td><code><font face="新宋体">BIGINT </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">Float </font></code></td>
            <td><code><font face="新宋体">REAL </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">Double </font></code></td>
            <td><code><font face="新宋体">DOUBLE </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">byte[] </font></code></td>
            <td><code><font face="新宋体">VARBINARY 或 LONGVARBINARY </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">java.sql.Date </font></code></td>
            <td><code><font face="新宋体">DATE </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">java.sql.Time </font></code></td>
            <td><code><font face="新宋体">TIME </font></code></td>
        </tr>
        <tr>
            <td><code><font face="新宋体">java.sql.Timestamp </font></code></td>
            <td><code><font face="新宋体">TIMESTAMP </font></code></td>
        </tr>
    </tbody>
</table>
<p>注意，<code><font face="新宋体">String</font></code> 的映射通常为 <code><font face="新宋体">VARCHAR</font></code>，但如果所给的值超出了驱动程序对 <code><font face="新宋体">VARCHAR</font></code> 值所限定的极限值，则将转换为 <code><font face="新宋体">LONGVARCHAR</font></code>。对 <code><font face="新宋体">byte[]</font></code>、<code><font face="新宋体">VARBINARY</font></code> 和 <code><font face="新宋体">LONGVARBINARY</font></code> 值也一样。&nbsp;</p>
<p>&nbsp;</p>
<h3>8.6.5 由 setObject 所进行的转换</h3>
<code>
<p><code>&nbsp; </code><font face="宋体, MS Song">方法将 Java object 类型转换为 JDBC 类型。</font><a href="http://kummy.itpub.net/mapping.doc.html#1004752">8.6.2</a> 节中的表所示。</p>
<p>setObject</p>
<p>
<table border="3">
    <tbody>
        <tr>
            <th valign="top">　</th>
            <th valign="top"><font size="-1">T<br />
            I<br />
            N<br />
            Y<br />
            I<br />
            N<br />
            T </font></th>
            <th valign="top"><font size="-1">S<br />
            M<br />
            A<br />
            L<br />
            L<br />
            I<br />
            N<br />
            T </font></th>
            <th valign="top"><font size="-1">I<br />
            N<br />
            T<br />
            E<br />
            G<br />
            E<br />
            R </font></th>
            <th valign="top"><font size="-1">B<br />
            I<br />
            G<br />
            I<br />
            N<br />
            T </font></th>
            <th valign="top"><font size="-1">R<br />
            E<br />
            A<br />
            L </font></th>
            <th valign="top"><font size="-1">F<br />
            L<br />
            O<br />
            A<br />
            T </font></th>
            <th valign="top"><font size="-1">D<br />
            O<br />
            U<br />
            B<br />
            L<br />
            E </font></th>
            <th valign="top"><font size="-1">D<br />
            E<br />
            C<br />
            I<br />
            M<br />
            A<br />
            L </font></th>
            <th valign="top"><font size="-1">N<br />
            U<br />
            M<br />
            E<br />
            R<br />
            I<br />
            C</font></th>
            <th valign="top"><font size="-1">B<br />
            I<br />
            T</font></th>
            <th valign="top"><font size="-1">C<br />
            H<br />
            A<br />
            R </font></th>
            <th valign="top"><font size="-1">V<br />
            A<br />
            R<br />
            C<br />
            H<br />
            A<br />
            R</font></th>
            <th valign="top"><font size="-1">L<br />
            O<br />
            N<br />
            G<br />
            V<br />
            A<br />
            R<br />
            C<br />
            H<br />
            A<br />
            R </font></th>
            <th valign="top"><font size="-1">B<br />
            I<br />
            N<br />
            A<br />
            R<br />
            Y </font></th>
            <th valign="top"><font size="-1">V<br />
            A<br />
            R<br />
            B<br />
            I<br />
            N<br />
            A<br />
            R<br />
            Y </font></th>
            <th valign="top"><font size="-1">L<br />
            O<br />
            N<br />
            G<br />
            V<br />
            A<br />
            R<br />
            B<br />
            I<br />
            N<br />
            A<br />
            R<br />
            Y </font></th>
            <th valign="top"><font size="-1">D<br />
            A<br />
            T<br />
            E </font></th>
            <th valign="top"><font size="-1">T<br />
            I<br />
            M<br />
            E </font></th>
            <th valign="top"><font size="-1">T<br />
            I<br />
            M<br />
            E<br />
            S<br />
            T<br />
            A<br />
            M<br />
            P </font></th>
        </tr>
        <tr>
            <td>String </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
        </tr>
        <tr>
            <td>java.math.BigDecimal </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
        </tr>
        <tr>
            <td>Boolean </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
        </tr>
        <tr>
            <td>Integer </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
        </tr>
        <tr>
            <td>Long </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
            <td>　</td>
        </tr>
        <tr>
            <td>Float </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </td>
            <td>x </t</td></tr></tbody></table></p></code></a>
          <br/>
          <span style="color:red;">
            <a href="http://lthu.javaeye.com/blog/147275#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
  