<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>wlcome998</title>
    <description>与同道中人共谋技术的进步</description>
    <link>http://wlcome998.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>Ajax技术和DWR框架介绍</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/173421" style="color:red;">http://wlcome998.javaeye.com/blog/173421</a>&nbsp;
          发表时间: 2008年03月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Ajax不是一种技术。实际上，它由几种蓬勃发展的技术以新的强大方式组合而成。Ajax包含：<br />XHTML：对应W3C的XHTML规范，目前是XHTML1.0。<br />CSS：对应W3C的CSS规范，目前是CSS2.0<br />DOM：这里的DOM主要是指HTML DOM，XML DOM包括在下面的XML中<br />JavaScript：对应于ECMA的ECMAScript规范<br />XML：对应W3C的XML DOM、XSLT、XPath等等规范<br />XMLHttpRequest：对应WhatWG的Web Applications1.0规范（http://whatwg.org/specs/web-apps/current-work/）的一部分<br />除了XMLHttpRequest以外，所有的技术都是目前已经广泛使用，得到了广泛理解的基于Web标准的技术。几乎所有主流的浏览器，例如IE、Firefox、Netscape、 Opera、Safari全部都支持XMLHttpRequest技术。所以Ajax就是目前做Web开发最符合标准的技术。<br />Ajax应用与传统的Web应用的区别主要在3个地方：<br />1. 不刷新整个页面，在页面内与服务器通信。<br />2  使用异步方式与服务器通信，不需要打断用户的操作，具有更加迅速的的响应能力。<br />3. 应用仅由少量页面组成。大部分交互在页面之内完成，不需要切换整个页面。<br />Ajax工作流程图见图1<br />    DWR是在Apache许可下的一个开源的解决方案，DWR是一个开源的类库,可以帮助开发人员开发包含AJAX技术的网站.它可以允许在浏览器里的代码使用运行在WEB服务器上的JAVA函数,就像它就在浏览器里一样。DWR通过JavaScript直接调用远程组件可以减少Web开发的时间，特别对于那些具有和用户频繁交互的Web应用程序。DWR使得浏览器不用刷新页面就可以从远程Web服务器取得用户需的数据，这种无刷新页面的交互方式大大提高Web页面的响应时间。<br /><br />DWR的配置文件如下：<br />&lt;dwr><br />  &lt;init><br />    &lt;creator id="..." class="..."/><br />    &lt;converter id="..." class="..."/><br />  &lt;/init><br />  &lt;allow><br />    &lt;create creator="..." javascript="..." scope="..."><br />      &lt;param name="..." value="..."/><br />    &lt;/create><br />    &lt;convert convertor="..." match="..."/><br />  &lt;/allow><br />  &lt;signatures><br />    ...<br />  &lt;/signatures><br />&lt;/dwr><br /><br />  图2是DWR的工作图（续）
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/173421#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</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, 18 Mar 2008 15:43:07 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/173421</link>
        <guid>http://wlcome998.javaeye.com/blog/173421</guid>
      </item>
      <item>
        <title>关于Hibernate连接池的问题</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/166955" style="color:red;">http://wlcome998.javaeye.com/blog/166955</a>&nbsp;
          发表时间: 2008年03月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          以前看过别人在Tomcat中使用proxy模式操作DBCP连接池，很方便，即在当前请求连接池数大于连接池池中的数目时，可以在程序中使用DataSource.setMaxActive()函数动态的修改DBCP的最大连接数，<br />想请问下在Hibernate3中所带的c3p0以及proxool连接池是否可以在程序中这样动态的修改连接池的最大和最小连接数。恳请指点
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/166955#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/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 03 Mar 2008 15:00:41 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/166955</link>
        <guid>http://wlcome998.javaeye.com/blog/166955</guid>
      </item>
      <item>
        <title>两个Hibernate中的问题</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/150652" style="color:red;">http://wlcome998.javaeye.com/blog/150652</a>&nbsp;
          发表时间: 2007年12月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          想问两个所遇到的困惑问题<br />1。在Hibernate中存在三种状态，transient（瞬时态）、persistent（持久态）、detached（脱管态）<br />瞬时态是保存在内存，当调用save时，瞬时态与session相关联成为持久态，将保存在数据库中，但是当session关闭时，将清空缓存，这是对象将成为脱管态，脱管态一般是存放在什么位置？<br />2.如果我需要使用两个数据库，一个是远程的数据库，一个是本地的数据库，之间可能还需要存在通信，这种情况使用Hibernate会不会很麻烦。
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/150652#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><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><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 25 Dec 2007 10:42:45 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/150652</link>
        <guid>http://wlcome998.javaeye.com/blog/150652</guid>
      </item>
      <item>
        <title>请教一个系统设计的问题</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/146240" style="color:red;">http://wlcome998.javaeye.com/blog/146240</a>&nbsp;
          发表时间: 2007年12月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          当使用Hibernate开源框架去做一个大中型系统的持久层时，我们一开始做的究竟应该是先设计数据库，然后按照数据库，使用工具将数据库映射成对象；还是完全撇开传统的关系数据库思想，使用Evans DDD的设计先建立实体之间关系图（或建立域模型），那么之后的数据库应如何生成，感觉始终都要面对RDB设计这样的问题。比较RDB是主流的数据库。<br />
不知道大家在平时的设计时一般按哪样的流程去做，能否介绍下大家在使用Hibernate设计时的流程和思路。<br />
最近一直在思考，如何使得关系数据库设计和Hibernate理念结合后产生的性能最好，能体现出Hibernate的优势和性能。
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/146240#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</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>Wed, 05 Dec 2007 17:02:11 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/146240</link>
        <guid>http://wlcome998.javaeye.com/blog/146240</guid>
      </item>
      <item>
        <title>问一个系统设计的问题</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/146238" style="color:red;">http://wlcome998.javaeye.com/blog/146238</a>&nbsp;
          发表时间: 2007年12月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          当使用Hibernate开源框架去做一个大中型系统的持久层时，我们一开始做的究竟应该是先设计数据库，然后按照数据库，使用工具将数据库映射成对象；还是完全撇开传统的关系数据库思想，先建立实体之间关系图（或建立域模型），然后根据该模型在设计数据库。<br />
不知道大家在平时的设计时一般按哪样的流程去做，能否介绍下大家在使用Hibernate设计时的流程和思路。<br />
最近一直在思考，如何使得数据库设计和Hibernate理念结合后产生的性能最好，能体现出Hibernate的优势和性能。
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/146238#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><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 05 Dec 2007 16:58:53 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/146238</link>
        <guid>http://wlcome998.javaeye.com/blog/146238</guid>
      </item>
      <item>
        <title>【转】数据库设计三大范式应用实例剖析</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/136258" style="color:red;">http://wlcome998.javaeye.com/blog/136258</a>&nbsp;
          发表时间: 2007年10月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Verdana"><font face="Verdana">
<p>&nbsp;&nbsp; <a href="http://www.itisedu.com/phrase/200604241401205.html" target="_new">第二范式</a>（<a href="http://www.itisedu.com/phrase/200604171811355.html" target="_new">2NF</a>）是在<a href="http://www.itisedu.com/phrase/200604241400035.html" target="_new">第一范式</a>（<a href="http://www.itisedu.com/phrase/200604171759045.html" target="_new">1NF</a>）的基础上建立起来的，即满足第二<a href="http://www.itisedu.com/phrase/200604241409355.html" target="_new">范式</a>（2NF）必须先满足第一范式（1NF）。第二范式（2NF）要求<a href="http://www.itisedu.com/phrase/200602271218062.html" target="_new">数据库</a>表 中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列，以存储各个实例的惟一标识。如图3-2 员工信息表中加上了员工编号（emp_id）列，因为每个员工的员工编号是惟一的，因此每个员工可以被惟一区分。这个惟一属性列被称为主关键字或主键、主 码。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二范式（2NF）要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性，如果存在，那么这个属性和主关键字的这一部 分应该分离出来形成一个新的实体，新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列，以存储各个实例的惟一标识。简而言之，第二范式 就是非主属性非部分依赖于主关键字。</p>
</font> </font>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.itisedu.com/phrase/200604171749365.html" target="_new">设计范式</a>是符合某一种级别的关系<a href="http://www.itisedu.com/phrase/200603061709535.html" target="_new">模式</a>的集合。构造数据库必须遵循一定的规则。在关系数据库中，这种规则就是范式。关系数据库中的关系必须满足一定的要求，即满足不同的范式。目前关系数据库有六种范式：第一范式（1NF）、第二范式（2NF）、<a href="http://www.itisedu.com/phrase/200604241402075.html" target="_new">第三范式</a>（<a href="http://www.itisedu.com/phrase/200604172019525.html" target="_new">3NF</a>）、第四范式（4NF）、第五范式（5NF）和第六范式（6NF）。满足最低要求的范式是第一范式（1NF）。在第一范式的基础上进一步满足更多要求的称为第二范式（2NF），其余范式以次<a href="http://www.itisedu.com/phrase/200603090857555.html" target="_new">类</a>推。一般说来，数据库只需满足第三范式（3NF）就行了。下面我们举例介绍第一范式（1NF）、第二范式（2NF）和第三范式（3NF）。</font></font></p>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在创建一个数据库的过程中，范化是将其转化为一些表的过程，这种方法可以使从数据库得到的结果更加明确。这样可能使数据库产生重复数据，从而导致创建多余 的表。范化是在识别数据库中的数据元素、关系，以及定义所需的表和各表中的项目这些初始工作之后的一个细化的过程。</font></font></p>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面是范化的一个例子　　Customer 　　Item purchased 　　 Purchase price 　　Thomas 　　　Shirt 　　　　　　　$40 　　Maria Tennis shoes 　　　 $35 　　　Evelyn 　　 Shirt $40　　Pajaro Trousers $25 　　</font></font></p>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果上面这个表用于保存物品的价格，而你想要删除其中的一个顾客，这时你就必须同时删除一个价格。范化就是要解决这个问题，你可以将这个表化为两个表，一 个用于存储每个顾客和他所买物品的信息，另一个用于存储每件产品和其价格的信息，这样对其中一个表做添加或删除操作就不会影响另一个表。<br />
<br />
<strong><u>关系数据库的几种设计范式介绍</u></strong></font></font></p>
<font face="Verdana"><font face="Verdana"> </font></font>
<p><font face="Verdana"><font face="Verdana"><br />
1 第一范式（1NF）</font></font></p>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在任何一个关系数据库中，第一范式（1NF）是对关系模式的基本要求，不满足第一范式（1NF）的数据库就不是关系数据库。</font></font></p>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所谓第一范式（1NF）是指数据库表的每一列都是不可分割的基本数据项，同一列中不能有多个值，即实体中的某个属性不能有多个值或者不能有重复的属性。如 果出现重复的属性，就可能需要定义一个新的实体，新的实体由重复的属性构成，新实体与原实体之间为一对多关系。在第一范式（1NF）中表的每一行只包含一 个实例的信息。例如，对于图3-2 中的员工信息表，不能将员工信息都放在一列中显示，也不能将其中的两列或多列在一列中显示；员工信息表的每一行只表示一个员工的信息，一个员工的信息在表 中只出现一次。简而言之，第一范式就是无重复的列。</font></font></p>
<p><font face="Verdana"><font face="Verdana">2 第二范式（2NF）</font></font></p>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二范式（2NF）是在第一范式（1NF）的基础上建立起来的，即满足第二范式（2NF）必须先满足第一范式（1NF）。第二范式（2NF）要求数据库表 中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列，以存储各个实例的惟一标识。如图3-2 员工信息表中加上了员工编号（emp_id）列，因为每个员工的员工编号是惟一的，因此每个员工可以被惟一区分。这个惟一属性列被称为主关键字或主键、主 码。</font></font></p>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二范式（2NF）要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性，如果存在，那么这个属性和主关键字的这一部 分应该分离出来形成一个新的实体，新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列，以存储各个实例的惟一标识。简而言之，第二范式 就是非主属性非部分依赖于主关键字。</font></font></p>
<p><font face="Verdana"><font face="Verdana">3 第三范式（3NF）</font></font></p>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 满足第三范式（3NF）必须先满足第二范式（2NF）。简而言之，第三范式（3NF）要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。例 如，存在一个部门信息表，其中每个部门有部门编号（dept_id）、部门名称、部门简介等信息。那么在图3-2的员工信息表中列出部门编号后就不能再将 部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表，则根据第三范式（3NF）也应该构建它，否则就会有大量的数据冗余。简 而言之，第三范式就是属性不依赖于其它非主属性。 </font></font></p>
<p><font face="Verdana"><font face="Verdana"><font face="Verdana"><strong><u><a href="http://www.itisedu.com/phrase/200603011123415.html" target="_new">数据库设计</a>三大范式应用实例剖析</u></strong> </font></font></font></p>
<p><font face="Verdana"><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.itisedu.com/phrase/200604241410255.html" target="_new">数据库的设计范式</a>是 数据库设计所需要满足的规范，满足这些规范的数据库是简洁的、结构明晰的，同时，不会发生插入（insert）、删除（delete）和更新 （update）操作异常。反之则是乱七八糟，不仅给数据库的编程人员制造麻烦，而且面目可憎，可能存储了大量不需要的冗余信息。 <br />
<br />
设计范式是不是很难懂呢？非也，大学教材上给我们一堆数学公式我们当然看不懂，也记不住。所以我们很多人就根本不按照范式来设计数据库。 <br />
<br />
实质上，设计范式用很形象、很简洁的话语就能说清楚，道明白。本文将对范式进行通俗地说明，并以笔者曾经设计的一个简单论坛的数据库为例来讲解怎样将这些范式应用于实际工程。 <br />
<br />
<strong>　　 范式说明 </strong><br />
<br />
第一范式（1NF）：数据库表中的字段都是单一属性的，不可再分。这个单一属性由基本<a href="http://www.itisedu.com/phrase/200603051002565.html" target="_new">类型</a>构成，包括整型、实数、字符型、逻辑型、日期型等。 <br />
<br />
例如，如下的数据库表是符合第一范式的： <br />
<br />
<table cellspacing="0" border="1" align="center" height="43" cellpadding="2">
    <tbody>
        <tr>
            <td height="18">字段1 </td>
            <td>字段2 </td>
            <td>字段3 </td>
            <td>字段4 </td>
        </tr>
        <tr>
            <td height="23">　　 </td>
            <td>　　 </td>
            <td>　　 </td>
            <td>　　 </td>
        </tr>
    </tbody>
</table>
<br />
而这样的数据库表是不符合第一范式的： <br />
<br />
<table cellspacing="0" border="1" align="center" height="25" cellpadding="2">
    <tbody>
        <tr>
            <td>字段1 </td>
            <td>字段2 </td>
            <td colspan="2">字段3 </td>
            <td>字段4 </td>
        </tr>
        <tr>
            <td>　　 </td>
            <td>　　 </td>
            <td>字段3.1 </td>
            <td>字段3.2 </td>
            <td>　　 </td>
        </tr>
    </tbody>
</table>
</font></font></p>
<p class="main"><font face="Verdana"><font face="Verdana"><br />
很显然，在当前的任何关系<a href="http://www.itisedu.com/phrase/200603011033425.html" target="_new">数据库管理系统</a>（<a href="http://www.itisedu.com/phrase/200604221337185.html" target="_new">DBMS</a>）中，傻瓜也不可能做出不符合第一范式的数据库，因为这些DBMS不允许你把数据库表的一列再分成二列或多列。因此，你想在现有的DBMS中设计出不符合第一范式的数据库都是不可能的。 <br />
<br />
第二范式（2NF）：数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖（部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况），也即所有非关键字段都完全依赖于任意一组候选关键字。 <br />
<br />
假定选课关系表为SelectCourse(学号, 姓名, 年龄, 课程名称, 成绩, 学分)，关键字为组合关键字(学号, 课程名称)，因为存在如下决定关系： <br />
<br />
(学号, 课程名称) &rarr; (姓名, 年龄, 成绩, 学分) <br />
<br />
这个数据库表不满足第二范式，因为存在如下决定关系： <br />
<br />
(课程名称) &rarr; (学分) <br />
<br />
(学号) &rarr; (姓名, 年龄) <br />
<br />
即存在组合关键字中的字段决定非关键字的情况。 <br />
<br />
由于不符合2NF，这个选课关系表会存在如下问题： <br />
<br />
(1) 数据冗余： <br />
<br />
同一门课程由n个学生选修，&quot;学分&quot;就重复n-1次；同一个学生选修了m门课程，姓名和年龄就重复了m-1次。 <br />
<br />
(2) 更新异常： <br />
<br />
若调整了某门课程的学分，数据表中所有行的&quot;学分&quot;值都要更新，否则会出现同一门课程学分不同的情况。 <br />
<br />
(3) 插入异常： <br />
<br />
假设要开设一门新的课程，暂时还没有人选修。这样，由于还没有&quot;学号&quot;关键字，课程名称和学分也无法记录入数据库。 <br />
<br />
(4) 删除异常： <br />
<br />
假设一批学生已经完成课程的选修，这些选修记录就应该从数据库表中删除。但是，与此同时，课程名称和学分信息也被删除了。很显然，这也会导致插入异常。 <br />
<br />
把选课关系表SelectCourse改为如下三个表： <br />
<br />
学生：Student(学号, 姓名, 年龄)； <br />
<br />
课程：Course(课程名称, 学分)； <br />
<br />
选课关系：SelectCourse(学号, 课程名称, 成绩)。 <br />
<br />
这样的数据库表是符合第二范式的， 消除了数据冗余、更新异常、插入异常和删除异常。 <br />
<br />
另外，所有单关键字的数据库表都符合第二范式，因为不可能存在组合关键字。 <br />
<br />
第三范式（3NF）：在第二范式的基础上，数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖，指的是如果 存在&quot;A &rarr; B &rarr; C&quot;的决定关系，则C传递函数依赖于A。因此，满足第三范式的数据库表应该不存在如下依赖关系： <br />
<br />
关键字段 &rarr; 非关键字段x &rarr; 非关键字段y <br />
<br />
假定学生关系表为Student(学号, 姓名, 年龄, 所在学院, 学院地点, 学院电话)，关键字为单一关键字&quot;学号&quot;，因为存在如下决定关系： <br />
<br />
(学号) &rarr; (姓名, 年龄, 所在学院, 学院地点, 学院电话) <br />
<br />
这个数据库是符合2NF的，但是不符合3NF，因为存在如下决定关系： <br />
<br />
(学号) &rarr; (所在学院) &rarr; (学院地点, 学院电话) <br />
<br />
即存在非关键字段&quot;学院地点&quot;、&quot;学院电话&quot;对关键字段&quot;学号&quot;的传递函数依赖。 <br />
<br />
它也会存在数据冗余、更新异常、插入异常和删除异常的情况，读者可自行分析得知。 <br />
<br />
把学生关系表分为如下两个表： <br />
<br />
学生：(学号, 姓名, 年龄, 所在学院)； <br />
<br />
学院：(学院, 地点, 电话)。 <br />
<br />
这样的数据库表是符合第三范式的，消除了数据冗余、更新异常、插入异常和删除异常。 <br />
<br />
鲍依斯-科得范式（BCNF）：在第三范式的基础上，数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖则符合第三范式。 <br />
<br />
假设仓库管理关系表为StorehouseManage(仓库ID, 存储物品ID, 管理员ID, 数量)，且有一个管理员只在一个仓库工作；一个仓库可以存储多种物品。这个数据库表中存在如下决定关系： <br />
<br />
(仓库ID, 存储物品ID) &rarr;(管理员ID, 数量) <br />
<br />
(管理员ID, 存储物品ID) &rarr; (仓库ID, 数量) <br />
<br />
所以，(仓库ID, 存储物品ID)和(管理员ID, 存储物品ID)都是StorehouseManage的候选关键字，表中的唯一非关键字段为数量，它是符合第三范式的。但是，由于存在如下决定关系： <br />
<br />
(仓库ID) &rarr; (管理员ID) <br />
<br />
(管理员ID) &rarr; (仓库ID) <br />
<br />
即存在关键字段决定关键字段的情况，所以其不符合BCNF范式。它会出现如下异常情况： <br />
<br />
(1) 删除异常： <br />
<br />
当仓库被清空后，所有&quot;存储物品ID&quot;和&quot;数量&quot;信息被删除的同时，&quot;仓库ID&quot;和&quot;管理员ID&quot;信息也被删除了。 <br />
<br />
(2) 插入异常： <br />
<br />
当仓库没有存储任何物品时，无法给仓库分配管理员。 <br />
<br />
(3) 更新异常： <br />
<br />
如果仓库换了管理员，则表中所有行的管理员ID都要修改。 <br />
<br />
把仓库管理关系表分解为二个关系表： <br />
<br />
仓库管理：StorehouseManage(仓库ID, 管理员ID)； <br />
<br />
仓库：Storehouse(仓库ID, 存储物品ID, 数量)。 <br />
<br />
这样的数据库表是符合BCNF范式的，消除了删除异常、插入异常和更新异常。 </font></font></p>
<p><font face="Verdana"><font face="Verdana"><strong>　　 范式应用 </strong><br />
<br />
我们来逐步搞定一个论坛的数据库，有如下信息： <br />
<br />
（1） 用户：用户名，email，主页，电话，联系地址 <br />
<br />
（2） 帖子：发帖标题，发帖内容，回复标题，回复内容 <br />
<br />
第一次我们将数据库设计为仅仅存在表： <br />
</font></font></p>
<p>
<table cellspacing="0" border="1" align="center" height="25" cellpadding="2">
    <tbody>
        <tr>
            <td>用户名 </td>
            <td>email </td>
            <td>主页 </td>
            <td>电话 </td>
            <td>联系地址 </td>
            <td>发帖标题 </td>
            <td>发帖内容 </td>
            <td>回复标题 </td>
            <td>回复内容 </td>
        </tr>
    </tbody>
</table>
<font face="Verdana"><font face="Verdana"><br />
这个数据库表符合第一范式，但是没有任何一组候选关键字能决定数据库表的整行，唯一的关键字段用户名也不能完全决定整个元组。我们需要增加&quot;发帖ID&quot;、&quot;回复ID&quot;字段，即将表修改为： <br />
<br />
<table cellspacing="0" border="1" align="center" height="25" cellpadding="2">
    <tbody>
        <tr>
            <td>用户名 </td>
            <td>email </td>
            <td>主页 </td>
            <td>电话 </td>
            <td>联系地址 </td>
            <td>发帖ID </td>
            <td>发帖标题 </td>
            <td>发帖内容 </td>
            <td>回复ID </td>
            <td>回复标题 </td>
            <td>回复内容 </td>
        </tr>
    </tbody>
</table>
<br />
这样数据表中的关键字(用户名，发帖ID，回复ID)能决定整行： <br />
<br />
(用户名,发帖ID,回复ID) &rarr; (email,主页,电话,联系地址,发帖标题,发帖内容,回复标题,回复内容) <br />
<br />
但是，这样的设计不符合第二范式，因为存在如下决定关系： <br />
<br />
(用户名) &rarr; (email,主页,电话,联系地址) <br />
<br />
(发帖ID) &rarr; (发帖标题,发帖内容) <br />
<br />
(回复ID) &rarr; (回复标题,回复内容) <br />
<br />
即非关键字段部分函数依赖于候选关键字段，很明显，这个设计会导致大量的数据冗余和操作异常。 <br />
<br />
我们将数据库表分解为（带下划线的为关键字）： <br />
<br />
（1） 用户信息：用户名，email，主页，电话，联系地址 <br />
<br />
（2） 帖子信息：发帖ID，标题，内容 <br />
<br />
（3） 回复信息：回复ID，标题，内容 <br />
<br />
（4） 发贴：用户名，发帖ID <br />
<br />
（5） 回复：发帖ID，回复ID <br />
<br />
这样的设计是满足第1、2、3范式和BCNF范式要求的，但是这样的设计是不是最好的呢？ <br />
<br />
不一定。 <br />
<br />
观察可知，第4项&quot;发帖&quot;中的&quot;用户名&quot;和&quot;发帖ID&quot;之间是1：N的关系，因此我们可以把&quot;发帖&quot;合并到第2项的&quot;帖子信息&quot;中；第5项&quot;回复&quot;中的&quot; 发帖ID&quot;和&quot;回复ID&quot;之间也是1：N的关系，因此我们可以把&quot;回复&quot;合并到第3项的&quot;回复信息&quot;中。这样可以一定量地减少数据冗余，新的设计为： <br />
<br />
（1） 用户信息：用户名，email，主页，电话，联系地址 <br />
<br />
（2） 帖子信息：用户名，发帖ID，标题，内容 <br />
<br />
（3） 回复信息：发帖ID，回复ID，标题，内容 <br />
<br />
数据库表1显然满足所有范式的要求； <br />
<br />
数据库表2中存在非关键字段&quot;标题&quot;、&quot;内容&quot;对关键字段&quot;发帖ID&quot;的部分函数依赖，即不满足第二范式的要求，但是这一设计并不会导致数据冗余和操作异常； <br />
<br />
数据库表3中也存在非关键字段&quot;标题&quot;、&quot;内容&quot;对关键字段&quot;回复ID&quot;的部分函数依赖，也不满足第二范式的要求，但是与数据库表2相似，这一设计也不会导致数据冗余和操作异常。 <br />
<br />
由此可以看出，并不一定要强行满足范式的要求，对于1：N关系，当1的一边合并到N的那边后，N的那边就不再满足第二范式了，但是这种设计反而比较好！ <br />
<br />
对于M：N的关系，不能将M一边或N一边合并到另一边去，这样会导致不符合范式要求，同时导致操作异常和数据冗余。 <br />
对于1：1的关系，我们可以将左边的1或者右边的1合并到另一边去，设计导致不符合范式要求，但是并不会导致操作异常和数据冗余。 <br />
<br />
<strong>　　 结论 </strong><br />
<br />
满足范式要求的数据库设计是结构清晰的，同时可避免数据冗余和操作异常。这并意味着不符合范式要求的设计一定是错误的，在数据库表中存在1：1或1：N关系这种较特殊的情况下，合并导致的不符合范式要求反而是合理的。 <br />
<br />
在我们设计数据库的时候，一定要时刻考虑范式的要求。</font></font></p>
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/136258#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><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><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 29 Oct 2007 10:56:13 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/136258</link>
        <guid>http://wlcome998.javaeye.com/blog/136258</guid>
      </item>
      <item>
        <title>【原创】ANTLR编译器以及在HQL中应用（一）</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/124933" style="color:red;">http://wlcome998.javaeye.com/blog/124933</a>&nbsp;
          发表时间: 2007年09月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p class="MsoNormal"><font size="2"><span>什么是</span><span lang="EN-US">ANTLR</span><span>？</span></font></p>
<p><font size="2"><span new="" times="" lang="EN-US" roman="">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ANTLR, </span><span>语言识别的另一个工具</span><span new="" times="" lang="EN-US" roman="">(ANother Tool for Language Recognition)，</span><span>是一种语言工具，它提供了一个框架，可以通过包含</span><span new="" times="" lang="EN-US" roman="">Java,C++,</span><span>或</span><span new="" times="" lang="EN-US" roman="">C#</span><span>动作的语法描述来构造语言识别器，编译器和解释器。</span><span new="" times="" lang="EN-US" roman="">它是</span></font><font size="2">由Terence Parr 领导开发（以前叫做PCCTS，<font color="#cc0033">Purdue</font> Compiler Construction Tool Set，普渡大学编译器构建工具集），也是一种分析器自动生成工具，它可以接受语言的文法描述，并能产生识别这些语言的程序。</font></p>
<p class="MsoNormal"><font size="2"><span lang="EN-US">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 相比于YACC</span><span>使用的</span><span lang="EN-US">LR/LALR</span><span>的算法，ANTLR通过更好的灵活性、错误处理机制、简易的调式部分来做递归下降的语法分析。这里介绍的是</span><span lang="EN-US">ANTLR</span><span>结合了手工语法处理和语法生成器的方便。</span><span lang="EN-US">ANTLR</span><span>比其他语言工具容易使用。</span></font></p>
<p class="MsoNormal"><font size="2"><span>&nbsp;&nbsp;&nbsp; ANTLR采用的是top-down的递归下降LL分析方法，而不是表驱动的LL/LR分析方法，相比较手工建立的递归下降分析器，表驱动的LL/LR分析器没有足够强的分析能力，并很难理解和调试。<br />
语法分析器不仅仅用于识别语言，还应于词法分析器交互，报告语法分析的错误，构建抽象语法树，调用各种用户的动作。<br />
&nbsp;&nbsp;&nbsp; ANTLR语法分析器用于构建可读的递归下降的LL(K)语法分析器，LL(K)相对于LL(1)更加易读，易于让人接受和易于表达，并且也减少左提供公因子的个数。当K&gt;1时，支持断言。<br />
&nbsp;&nbsp;&nbsp; ANTLR相比较于其他的语法分析器优点在于：<br />
1&nbsp;&nbsp;&nbsp; ANTLR集成了词法和语法的分析。<br />
2&nbsp;&nbsp; ANTLR接受由EBNF范式构建的语法。<br />
3&nbsp;&nbsp; ANTLR能自动构建语法抽象树。<br />
4&nbsp;&nbsp;&nbsp; ANTLR使用的是递归下降的语法分析器，因此语法规范和ANTLR输出之间的对应关系比较清楚。比较容易理解。<br />
5&nbsp;&nbsp;&nbsp; ANTLR能方便的自动和手工进行错误恢复和报错，自动机制能简单有效地分析许多语法情况:手动的机制被称为&ldquo;语法分析异常处理&rdquo;，简化了高质量的错误处理。<br />
6&nbsp;&nbsp;&nbsp; ANTLR允许每个语法规则都有参数和返回值，方便在语法分析中的属性传递。一个规则的参数会被转换成一个函数的参数，ANTLR中可以有多个返回值。<br />
7&nbsp;&nbsp; ANTLR还有众多的功能，使其成为一个产品，而不仅仅是研究性的工程。而且ANTLR是用java语言写的，可方便移植和调式。很容易整合到项目的应用程序中。</span></font></p>
<p class="MsoNormal"><font size="2"><span>&nbsp;&nbsp;&nbsp; ANTLR并不是使用纯正的LL(K)算法，它使用了最小lookahead的决策算法对LL(K)算法进行改进，加速了语法的分析和分析速度，并减少了 分析代码的尺寸，但对于大多数的决策，向前lookahead 1个token已经足够，因此ANTLR语法分析器的效率近似于LL(1)递归下降分析器。也使其复杂度从O(m^K)降到O(m*k);因此也大大提高 了分析效率。</span></font></p>
<p class="MsoNormal"><font size="2"><span>&nbsp;&nbsp;&nbsp; 此外，ANLLR的LL(K)算法还有一个重要特性，即支持断言，能有效的消除冲突，断言分为语法断言和语义断言。</span></font></p>
<p class="MsoNormal"><font size="2"><span>&nbsp;&nbsp;&nbsp; 以下三部分将就ANTLR的Lexer、parser以及TreeParser做详细具体的介绍（待续） </span></font></p>
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/124933#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 18 Sep 2007 11:44:59 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/124933</link>
        <guid>http://wlcome998.javaeye.com/blog/124933</guid>
      </item>
      <item>
        <title>[转]关于HQL语言的一些小结</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/124923" style="color:red;">http://wlcome998.javaeye.com/blog/124923</a>&nbsp;
          发表时间: 2007年09月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong><span style="font-size: 14pt;">HQL</span><span style="font-size: 14pt;">查询：</span></strong>
<div style="text-indent: 24.1pt;"><strong><span style="font-size: 12pt;">Criteria</span></strong><strong><span style="font-size: 12pt;">查询对查询条件进行了面向对象封装，符合编程人员的思维方式，不过</span></strong><strong><span style="font-size: 12pt;">HQL(Hibernate Query Lanaguage)</span></strong><strong><span style="font-size: 12pt;">查询提供了更加丰富的和灵活的查询特性，因此</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">将</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">查询方式立为官方推荐的标准查询方式，</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">查询在涵盖</span></strong><strong><span style="font-size: 12pt;">Criteria</span></strong><strong><span style="font-size: 12pt;">查询的所有功能的前提下，提供了类似标准</span></strong><strong><span style="font-size: 12pt;">SQL</span></strong><strong><span style="font-size: 12pt;">语句的查询方式，同时也提供了更加面向对象的封装。完整的</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">语句形势如下：</span></strong></div>
<div><strong><span style="font-size: 12pt;">Select/update/delete&hellip;&hellip; from &hellip;&hellip; where &hellip;&hellip; group by &hellip;&hellip; having &hellip;&hellip; order by &hellip;&hellip; asc/desc</span></strong></div>
<div><strong><span style="font-size: 12pt;">其中的</span></strong><strong><span style="font-size: 12pt;">update/delete</span></strong><strong><span style="font-size: 12pt;">为</span></strong><strong><span style="font-size: 12pt;">Hibernate3</span></strong><strong><span style="font-size: 12pt;">中所新添加的功能，可见</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">查询非常类似于标准</span></strong><strong><span style="font-size: 12pt;">SQL</span></strong><strong><span style="font-size: 12pt;">查询。由于</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">查询在整个</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">实体操作体系中的核心地位，这一节我将专门围绕</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">操作的具体技术细节进行讲解。</span></strong></div>
<div style="margin-left: 18pt; text-indent: -18pt;"><strong><span style="font-size: 12pt;">1、&nbsp;</span></strong><strong><span style="font-size: 12pt;">实体查询：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">有关实体查询技术，其实我们在先前已经有多次涉及，比如下面的例子：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">String hql=&rdquo;from User user &rdquo;;</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">List list=session.CreateQuery(hql).list();</span></strong></div>
<div><strong><span style="font-size: 12pt;">上面的代码执行结果是，查询出</span></strong><strong><span style="font-size: 12pt;">User</span></strong><strong><span style="font-size: 12pt;">实体对象所对应的所有数据，而且将数据封装成</span></strong><strong><span style="font-size: 12pt;">User</span></strong><strong><span style="font-size: 12pt;">实体对象，并且放入</span></strong><strong><span style="font-size: 12pt;">List</span></strong><strong><span style="font-size: 12pt;">中返回。这里需要注意的是，</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">的实体查询存在着对继承关系的判定，比如我们前面讨论映射实体继承关系中的</span></strong><strong><span style="font-size: 12pt; color: black;">Employee</span></strong><strong><span style="font-size: 12pt;">实体对象，它有两个子类分别是</span></strong><strong><span style="font-size: 12pt; color: black;">HourlyEmployee</span></strong><strong><span style="font-size: 12pt; color: black;">，</span></strong><strong><span style="font-size: 12pt; color: black;">SalariedEmployee,</span></strong><strong><span style="font-size: 12pt;">如果有这样的</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">语句：&ldquo;</span></strong><strong><span style="font-size: 12pt;">from <span style="color: black;">Employee</span></span></strong><strong><span style="font-size: 12pt;">&rdquo;</span></strong><strong><span style="font-size: 12pt;">,</span></strong><strong><span style="font-size: 12pt;">当执行检索时</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">会检索出所有</span></strong><strong><span style="font-size: 12pt; color: black;">Employee</span></strong><strong><span style="font-size: 12pt; color: black;">类型实体对象所对应的数据（包括它的子类</span></strong><strong><span style="font-size: 12pt; color: black;">HourlyEmployee</span></strong><strong><span style="font-size: 12pt; color: black;">，</span></strong><strong><span style="font-size: 12pt; color: black;">SalariedEmployee</span></strong><strong><span style="font-size: 12pt; color: black;">对应的数据）。</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">因为</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句与标准</span></strong><strong><span style="font-size: 12pt; color: black;">SQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句相似，所以我们也可以在</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句中使用</span></strong><strong><span style="font-size: 12pt; color: black;">where</span></strong><strong><span style="font-size: 12pt; color: black;">字句，并且可以在</span></strong><strong><span style="font-size: 12pt; color: black;">where</span></strong><strong><span style="font-size: 12pt; color: black;">字句中使用各种表达式，比较操作符以及使用&ldquo;</span></strong><strong><span style="font-size: 12pt; color: black;">and</span></strong><strong><span style="font-size: 12pt; color: black;">&rdquo;</span></strong><strong><span style="font-size: 12pt; color: black;">,&rdquo;or&rdquo;</span></strong><strong><span style="font-size: 12pt; color: black;">连接不同的查询条件的组合。看下面的一些简单的例子：</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">from User user where user.age=20;</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">from User user where user.age between 20 and 30;</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">from User user where user.age in(20,30);</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">from User user where user.name is null;</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">from User user where user.name like &lsquo;%zx%&rsquo;;</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">from User user where (user.age%2)=1;</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">from User user where user.age=20 and user.name like &lsquo;%zx%&rsquo;;</span></strong></div>
<div style="margin-left: 18pt; text-indent: -18pt;"><strong><span style="font-size: 12pt; color: black;">2、&nbsp;</span></strong><strong><span style="font-size: 12pt; color: black;">实体的更新和删除：</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">&nbsp;&nbsp; </span></strong><strong><span style="font-size: 12pt; color: black;">在继续讲解</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">其他更为强大的查询功能前，我们先来讲解以下利用</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">进行实体更新和删除的技术。这项技术功能是</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate3</span></strong><strong><span style="font-size: 12pt; color: black;">的新加入的功能，在</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate2</span></strong><strong><span style="font-size: 12pt; color: black;">中是不具备的。比如在</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate2</span></strong><strong><span style="font-size: 12pt; color: black;">中，如果我们想将数据库中所有</span></strong><strong><span style="font-size: 12pt; color: black;">18</span></strong><strong><span style="font-size: 12pt; color: black;">岁的用户的年龄全部改为</span></strong><strong><span style="font-size: 12pt; color: black;">20</span></strong><strong><span style="font-size: 12pt; color: black;">岁，那么我们要首先将年龄在</span></strong><strong><span style="font-size: 12pt; color: black;">18</span></strong><strong><span style="font-size: 12pt; color: black;">岁的用户检索出来，然后将他们的年龄修改为</span></strong><strong><span style="font-size: 12pt; color: black;">20</span></strong><strong><span style="font-size: 12pt; color: black;">岁，最后调用</span></strong><strong><span style="font-size: 12pt; color: black;">Session.update()</span></strong><strong><span style="font-size: 12pt; color: black;">语句进行更新。在</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate3</span></strong><strong><span style="font-size: 12pt; color: black;">中对这个问题提供了更加灵活和更具效率的解决办法，如下面的代码：</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">Transaction trans=session.beginTransaction();</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">String hql=&rdquo;update User user set user.age=20 where user.age=18&rdquo;;</span></strong></div>
<div><strong><span style="font-size: 12pt; color: red;">Query queryupdate=session.createQuery(hql);</span></strong></div>
<div><strong><span style="font-size: 12pt; color: red;">int ret=queryupdate.executeUpdate();</span></strong></div>
<div><strong><span style="font-size: 12pt;">trans.commit();</span></strong></div>
<div><strong><span style="font-size: 12pt;">通过这种方式我们可以在</span></strong><strong><span style="font-size: 12pt;">Hibernate3</span></strong><strong><span style="font-size: 12pt;">中，一次性完成批量数据的更新，对性能的提高是相当的可观。同样也可以通过类似的方式来完成</span></strong><strong><span style="font-size: 12pt;">delete</span></strong><strong><span style="font-size: 12pt;">操作，如下面的代码：</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">Transaction trans=session.beginTransaction();</span></strong></div>
<div><strong><span style="font-size: 12pt; color: black;">String hql=&rdquo;delete from User user where user.age=18&rdquo;;</span></strong></div>
<div><strong><span style="font-size: 12pt; color: red;">Query queryupdate=session.createQuery(hql);</span></strong></div>
<div><strong><span style="font-size: 12pt; color: red;">int ret=queryupdate.executeUpdate();</span></strong></div>
<div><strong><span style="font-size: 12pt;">trans.commit();</span></strong></div>
<div><strong><span style="font-size: 12pt;">如果你是逐个章节阅读的化，那么你一定会记起我在第二部分中有关批量数据操作的相关论述中，讨论过这种操作方式，这种操作方式在</span></strong><strong><span style="font-size: 12pt;">Hibernate3</span></strong><strong><span style="font-size: 12pt;">中称为</span></strong><strong><span style="font-size: 12pt;">bulk delete/update</span></strong><strong><span style="font-size: 12pt;">，这种方式能够在很大程度上提高操作的灵活性和运行效率，但是采用这种方式极有可能引起缓存同步上的问题</span></strong><strong><span style="font-size: 12pt;">(</span></strong><strong><span style="font-size: 12pt;">请参考相关论述</span></strong><strong><span style="font-size: 12pt;">)</span></strong><strong><span style="font-size: 12pt;">。</span></strong></div>
<div style="margin-left: 18pt; text-indent: -18pt;"><strong><span style="font-size: 12pt;">3、&nbsp;</span></strong><strong><span style="font-size: 12pt;">属性查询：</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;&nbsp; </span></strong><strong><span style="font-size: 12pt;">很多时候我们在检索数据时，并不需要获得实体对象所对应的全部数据，而只需要检索实体对象的部分属性所对应的数据。这时候就可以利用</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">属性查询技术，如下面程序示例：</span></strong></div>
<div><strong><span style="font-size: 12pt;">List list=session.createQuery(&ldquo;select user.name from User user &rdquo;).list();</span></strong></div>
<div><strong><span style="font-size: 12pt;">for(int i=0;i&lt;list.size();i++){</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;System.out.println(list.get(i));</span></strong></div>
<div><strong><span style="font-size: 12pt;">}</span></strong></div>
<div><strong><span style="font-size: 12pt;">我们只检索了</span></strong><strong><span style="font-size: 12pt;">User</span></strong><strong><span style="font-size: 12pt;">实体的</span></strong><strong><span style="font-size: 12pt;">name</span></strong><strong><span style="font-size: 12pt;">属性对应的数据，此时返回的包含结果集的</span></strong><strong><span style="font-size: 12pt;">list</span></strong><strong><span style="font-size: 12pt;">中每个条目都是</span></strong><strong><span style="font-size: 12pt;">String</span></strong><strong><span style="font-size: 12pt;">类型的</span></strong><strong><span style="font-size: 12pt;">name</span></strong><strong><span style="font-size: 12pt;">属性对应的数据。我们也可以一次检索多个属性，如下面程序：</span></strong></div>
<div><strong><span style="font-size: 12pt;">List list=session.createQuery(&ldquo;select user.name,user.age from User user &rdquo;).list();</span></strong></div>
<div><strong><span style="font-size: 12pt;">for(int i=0;i&lt;list.size();i++){</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;Object[] obj=(Object[])list.get(i);</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;System.out.println(obj[0]);</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;System.out.println(obj[1]);</span></strong></div>
<div><strong><span style="font-size: 12pt;">}</span></strong></div>
<div><strong><span style="font-size: 12pt;">此时返回的结果集</span></strong><strong><span style="font-size: 12pt;">list</span></strong><strong><span style="font-size: 12pt;">中，所包含的每个条目都是一个</span></strong><strong><span style="font-size: 12pt;">Object[]</span></strong><strong><span style="font-size: 12pt;">类型，其中包含对应的属性数据值。作为当今我们这一代深受面向对象思想影响的开发人员，可能会觉得上面返回</span></strong><strong><span style="font-size: 12pt;">Object[]</span></strong><strong><span style="font-size: 12pt;">不够符合面向对象风格，这时我们可以利用</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">提供的动态构造实例的功能对这些平面数据进行封装，如下面的程序代码：</span></strong></div>
<div><strong><span style="font-size: 12pt;">List list=session.createQuery(&ldquo;select new User(user.name,user.age) from User user &rdquo;).list();</span></strong></div>
<div><strong><span style="font-size: 12pt;">for(int i=0;i&lt;list.size();i++){</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;User user=(User)list.get(i);</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;System.out.println(user.getName());</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;System.out.println(user.getAge());</span></strong></div>
<div><strong><span style="font-size: 12pt;">}</span></strong></div>
<div><strong><span style="font-size: 12pt;">这里我们通过动态构造实例对象，对返回结果进行了封装，使我们的程序更加符合面向对象风格，但是这里有一个问题必须注意，那就是这时所返回的</span></strong><strong><span style="font-size: 12pt;">User</span></strong><strong><span style="font-size: 12pt;">对象，仅仅只是一个普通的</span></strong><strong><span style="font-size: 12pt;">Java</span></strong><strong><span style="font-size: 12pt;">对象而以，除了查询结果值之外，其它的属性值都为</span></strong><strong><span style="font-size: 12pt;">null</span></strong><strong><span style="font-size: 12pt;">（包括主键值</span></strong><strong><span style="font-size: 12pt;">id</span></strong><strong><span style="font-size: 12pt;">），也就是说不能通过</span></strong><strong><span style="font-size: 12pt;">Session</span></strong><strong><span style="font-size: 12pt;">对象对此对象执行持久化的更新操作。如下面的代码：</span></strong></div>
<div><strong><span style="font-size: 12pt;">List list=session.createQuery(&ldquo;select new User(user.name,user.age) from User user &rdquo;).list();</span></strong></div>
<div><strong><span style="font-size: 12pt;">for(int i=0;i&lt;list.size();i++){</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;User user=(User)list.get(i);</span></strong></div>
<div><strong><span style="font-size: 12pt;">&nbsp;user.setName(&ldquo;gam&rdquo;);</span></strong></div>
<div style="margin-left: 165.3pt; text-indent: -165.3pt;"><strong><span style="font-size: 12pt;">&nbsp;session.saveOrUpdate(user);<span style="color: red;">//</span></span></strong><strong><span style="font-size: 12pt; color: red;">这里将会实际执行一个</span></strong><strong><span style="font-size: 12pt; color: red;">save</span></strong><strong><span style="font-size: 12pt; color: red;">操作，而不会执行</span></strong><strong><span style="font-size: 12pt; color: red;">update</span></strong><strong><span style="font-size: 12pt; color: red;">操作，因为这个</span></strong><strong><span style="font-size: 12pt; color: red;">User</span></strong><strong><span style="font-size: 12pt; color: red;">对象的</span></strong><strong><span style="font-size: 12pt; color: red;">id</span></strong><strong><span style="font-size: 12pt; color: red;">属性为</span></strong><strong><span style="font-size: 12pt; color: red;">null</span></strong><strong><span style="font-size: 12pt; color: red;">，</span></strong><strong><span style="font-size: 12pt; color: red;">Hibernate</span></strong><strong><span style="font-size: 12pt; color: red;">会把它作为一个自由对象（请参考持久化对象状态部分的论述），因此会对它执行</span></strong><strong><span style="font-size: 12pt; color: red;">save</span></strong><strong><span style="font-size: 12pt; color: red;">操作。</span></strong></div>
<div><strong><span style="font-size: 12pt;">}</span></strong></div>
<div style="margin-left: 18pt; text-indent: -18pt;"><strong><span style="font-size: 12pt;">4、&nbsp;</span></strong><strong><span style="font-size: 12pt;">分组与排序</span></strong></div>
<div style="margin-left: 33.05pt; text-indent: -21pt;"><strong><span style="font-size: 12pt;">A、</span></strong><strong><span style="font-size: 12pt;">Order by</span></strong><strong><span style="font-size: 12pt;">子句：</span></strong></div>
<div style="margin-left: 12.05pt;"><strong><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; </span></strong><strong><span style="font-size: 12pt;">与</span></strong><strong><span style="font-size: 12pt;">SQL</span></strong><strong><span style="font-size: 12pt;">语句相似，</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">查询也可以通过</span></strong><strong><span style="font-size: 12pt;">order by</span></strong><strong><span style="font-size: 12pt;">子句对查询结果集进行排序，并且可以通过</span></strong><strong><span style="font-size: 12pt;">asc</span></strong><strong><span style="font-size: 12pt;">或者</span></strong><strong><span style="font-size: 12pt;">desc</span></strong><strong><span style="font-size: 12pt;">关键字指定排序方式，如下面的代码：</span></strong></div>
<div style="margin-left: 12.05pt;"><strong><span style="font-size: 12pt;">from User user order by user.name asc,user.age desc;</span></strong></div>
<div style="margin-left: 12.05pt;"><strong><span style="font-size: 12pt;">上面</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">查询语句，会以</span></strong><strong><span style="font-size: 12pt;">name</span></strong><strong><span style="font-size: 12pt;">属性进行升序排序，以</span></strong><strong><span style="font-size: 12pt;">age</span></strong><strong><span style="font-size: 12pt;">属性进行降序排序，而且与</span></strong><strong><span style="font-size: 12pt;">SQL</span></strong><strong><span style="font-size: 12pt;">语句一样，默认的排序方式为</span></strong><strong><span style="font-size: 12pt;">asc,</span></strong><strong><span style="font-size: 12pt;">即升序排序。</span></strong></div>
<div style="margin-left: 33.05pt; text-indent: -21pt;"><strong><span style="font-size: 12pt;">B、</span></strong><strong><span style="font-size: 12pt;">Group by</span></strong><strong><span style="font-size: 12pt;">子句与统计查询：</span></strong></div>
<div style="text-indent: 24.1pt;"><strong><span style="font-size: 12pt;">在</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">语句中同样支持使用</span></strong><strong><span style="font-size: 12pt;">group by</span></strong><strong><span style="font-size: 12pt;">子句分组查询，还支持</span></strong><strong><span style="font-size: 12pt;">group by</span></strong><strong><span style="font-size: 12pt;">子句结合聚集函数的分组统计查询，大部分标准的</span></strong><strong><span style="font-size: 12pt;">SQL</span></strong><strong><span style="font-size: 12pt;">聚集函数都可以在</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">语句中使用，比如：</span></strong><strong><span style="font-size: 12pt;">count(),sum(),max(),min(),avg()</span></strong><strong><span style="font-size: 12pt;">等。如下面的程序代码：</span></strong></div>
<div><strong><span style="font-size: 12pt;">String hql=&rdquo;select count(user),user.age from User user group by user.age having count(user)&gt;10 &rdquo;;</span></strong></div>
<div><strong><span style="font-size: 12pt;">List list=session.createQuery(hql).list();</span></strong></div>
<div style="margin-left: 33.05pt; text-indent: -21pt;"><strong><span style="font-size: 12pt;">C、</span></strong><strong><span style="font-size: 12pt;">优化统计查询：</span></strong></div>
<div style="margin-left: 12.05pt;"><strong><span style="font-size: 12pt;">假设我们现在有两张数据库表，分别是</span></strong><strong><span style="font-size: 12pt;">customer</span></strong><strong><span style="font-size: 12pt;">表和</span></strong><strong><span style="font-size: 12pt;">order</span></strong><strong><span style="font-size: 12pt;">表，它们的结构如下：</span></strong></div>
<table cellspacing="0" border="1" style="border: medium none ; border-collapse: collapse;" cellpadding="0">
    <tbody>
        <tr>
            <td valign="top" style="border: 1pt solid windowtext; padding: 0cm 5.4pt;">
            <div><strong><span style="font-size: 12pt;">customer</span></strong></div>
            </td>
        </tr>
        <tr>
            <td valign="top" style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt;">
            <div><strong><span style="font-size: 12pt;">ID&nbsp;varchar2(14)</span></strong></div>
            </td>
        </tr>
        <tr>
            <td valign="top" style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt;">
            <div><strong><span style="font-size: 12pt;">age&nbsp;number(10)</span></strong></div>
            </td>
        </tr>
        <tr>
            <td valign="top" style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt;">
            <div><strong><span style="font-size: 12pt;">name varchar2(20)</span></strong></div>
            </td>
        </tr>
    </tbody>
</table>
<div style="margin-left: 12.05pt;"><strong>&nbsp;</strong></div>
<table cellspacing="0" border="1" style="border: medium none ; border-collapse: collapse;" cellpadding="0">
    <tbody>
        <tr>
            <td valign="top" style="border: 1pt solid windowtext; padding: 0cm 5.4pt;">
            <div><strong><span style="font-size: 12pt;">order</span></strong></div>
            </td>
        </tr>
        <tr>
            <td valign="top" style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt;">
            <div><strong><span style="font-size: 12pt;">ID varchar2(14)</span></strong></div>
            </td>
        </tr>
        <tr>
            <td valign="top" style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt;">
            <div><strong><span style="font-size: 12pt;">order_number number(10)</span></strong></div>
            </td>
        </tr>
        <tr>
            <td valign="top" style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt;">
            <div><strong><span style="font-size: 12pt;">customer_ID varchar2(14)</span></strong></div>
            </td>
        </tr>
    </tbody>
</table>
<div style="margin-left: 12.05pt;"><strong><span style="font-size: 12pt;">现在有两条</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">查询语句，分别如下：</span></strong></div>
<div style="margin-left: 12.05pt;"><strong><span style="font-size: 12pt;">from Customer c inner join c.orders o group by c.age;(1)</span></strong></div>
<div style="margin-left: 12.05pt;"><strong>&nbsp;</strong></div>
<div style="margin-left: 12.05pt;"><strong><span style="font-size: 12pt;">select c.ID,c.name,c.age,o.ID,o.order_number,o.customer_ID</span></strong></div>
<div style="margin-left: 12.05pt;"><strong><span style="font-size: 12pt;">from Customer c inner join c.orders c group by c.age;(2)</span></strong></div>
<div style="margin-left: 12.05pt; text-indent: 24.1pt;"><strong><span style="font-size: 12pt;">这两条语句使用了</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">语句的内连接查询（我们将在</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">语句的连接查询部分专门讨论），现在我们可以看出这两条查询语句最后所返回的结果是一样的，但是它们其实是有明显区别的，语句（</span></strong><strong><span style="font-size: 12pt;">1</span></strong><strong><span style="font-size: 12pt;">）检索的结果会返回</span></strong><strong><span style="font-size: 12pt;">Customer</span></strong><strong><span style="font-size: 12pt;">与</span></strong><strong><span style="font-size: 12pt;">Order</span></strong><strong><span style="font-size: 12pt;">持久化对象，而且它们会被置于</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">的</span></strong><strong><span style="font-size: 12pt;">Session</span></strong><strong><span style="font-size: 12pt;">缓存之中，并且</span></strong><strong><span style="font-size: 12pt;">Session</span></strong><strong><span style="font-size: 12pt;">会负责它们在缓存中的唯一性以及与后台数据库数据的同步，只有事务提交后它们才会从缓存中被清除；而语句（</span></strong><strong><span style="font-size: 12pt;">2</span></strong><strong><span style="font-size: 12pt;">）返回的是关系数据而并非是持久化对象，因此它们不会占用</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">的</span></strong><strong><span style="font-size: 12pt;">Session</span></strong><strong><span style="font-size: 12pt;">缓存，只要在检索之后应用程序不在访问它们，它们所占用的内存就有可能被</span></strong><strong><span style="font-size: 12pt;">JVM</span></strong><strong><span style="font-size: 12pt;">的垃圾回收器回收，而且</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">不会同步对它们的修改。</span></strong></div>
<div style="margin-left: 12.05pt; text-indent: 24pt;"><strong><span style="font-size: 12pt;">在我们的系统开发中，尤其是</span></strong><strong><span style="font-size: 12pt;">Mis</span></strong><strong><span style="font-size: 12pt;">系统，不可避免的要进行统计查询的开发，这类功能有两个特点：第一数据量大；第二一般情况下都是只读操作而不会涉及到对统计数据进行修改，那么如果采用第一种查询方式，必然会导致大量持久化对象位于</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">的</span></strong><strong><span style="font-size: 12pt;">Session</span></strong><strong><span style="font-size: 12pt;">缓存中，而且</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">的</span></strong><strong><span style="font-size: 12pt;">Session</span></strong><strong><span style="font-size: 12pt;">缓存还要负责它们与数据库数据的同步。而如果采用第二种查询方式，显然就会提高查询性能，因为不需要</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">的</span></strong><strong><span style="font-size: 12pt;">Session</span></strong><strong><span style="font-size: 12pt;">缓存的管理开销，而且只要应用程序不在使用这些数据，它们所占用的内存空间就会被回收释放。</span></strong></div>
<div style="margin-left: 12.05pt; text-indent: 24pt;"><strong><span style="font-size: 12pt;">因此在开发统计查询系统时，尽量使用通过</span></strong><strong><span style="font-size: 12pt;">select</span></strong><strong><span style="font-size: 12pt;">语句写出需要查询的属性的方式来返回关系数据，而避免使用第一种查询方式返回持久化对象（这种方式是在有修改需求时使用比较适合），这样可以提高运行效率并且减少内存消耗。㊣</span></strong><strong>真正的高手并不是精通一切，而是精通在合适的场合使用合适的手段。</strong></div>
<div style="margin-left: 18pt; text-indent: -18pt;"><strong><span style="font-size: 12pt;">5、&nbsp;</span></strong><strong><span style="font-size: 12pt;">参数绑定：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">中对动态查询参数绑定提供了丰富的支持，那么什么是查询参数动态绑定呢？其实如果我们熟悉传统</span></strong><strong><span style="font-size: 12pt;">JDBC</span></strong><strong><span style="font-size: 12pt;">编程的话，我们就不难理解查询参数动态绑定，如下代码传统</span></strong><strong><span style="font-size: 12pt;">JDBC</span></strong><strong><span style="font-size: 12pt;">的参数绑定：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">PrepareStatement pre=connection.prepare(&ldquo;select * from User where user.name=?&rdquo;);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">pre.setString(1,&rdquo;zhaoxin&rdquo;);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">ResultSet rs=pre.executeQuery();</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">在</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">中也提供了类似这种的查询参数绑定功能，而且在</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">中对这个功能还提供了比传统</span></strong><strong><span style="font-size: 12pt;">JDBC</span></strong><strong><span style="font-size: 12pt;">操作丰富的多的特性，在</span></strong><strong><span style="font-size: 12pt;">Hibernate</span></strong><strong><span style="font-size: 12pt;">中共存在</span></strong><strong><span style="font-size: 12pt;">4</span></strong><strong><span style="font-size: 12pt;">种参数绑定的方式，下面我们将分别介绍：</span></strong></div>
<div style="margin-left: 54pt; text-indent: -36pt;"><strong><span style="font-size: 12pt;">A、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="font-size: 12pt;">按参数名称绑定：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">&nbsp;</span></strong><strong><span style="font-size: 12pt;">在HQL语句中定义命名参数要用&rdquo;:&rdquo;开头，形式如下：</span></strong></div>
<div style="margin-left: 218.65pt; text-indent: -200.7pt;"><strong><span style="font-size: 12pt;">&nbsp;</span></strong><strong><span style="font-size: 12pt;">Query query=session.createQuery(&ldquo;from User user where user.name=:customername and user:customerage=:age &rdquo;);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">&nbsp;query.setString(&ldquo;customername&rdquo;,name);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">&nbsp;query.setInteger(&ldquo;customerage&rdquo;,age);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">&nbsp;</span></strong><strong><span style="font-size: 12pt;">上面代码中用</span></strong><strong><span style="font-size: 12pt;">:customername</span></strong><strong><span style="font-size: 12pt;">和</span></strong><strong><span style="font-size: 12pt;">:customerage</span></strong><strong><span style="font-size: 12pt;">分别定义了命名参数</span></strong><strong><span style="font-size: 12pt;">customername</span></strong><strong><span style="font-size: 12pt;">和</span></strong><strong><span style="font-size: 12pt;">customerage</span></strong><strong><span style="font-size: 12pt;">，然后用</span></strong><strong><span style="font-size: 12pt;">Query</span></strong><strong><span style="font-size: 12pt;">接口的</span></strong><strong><span style="font-size: 12pt;">setXXX()</span></strong><strong><span style="font-size: 12pt;">方法设定名参数值，</span></strong><strong><span style="font-size: 12pt;">setXXX()</span></strong><strong><span style="font-size: 12pt;">方法包含两个参数，分别是命名参数名称和命名参数实际值。</span></strong></div>
<div style="margin-left: 54pt; text-indent: -36pt;"><strong><span style="font-size: 12pt;">B、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="font-size: 12pt;">按参数位置邦定：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">&nbsp;</span></strong><strong><span style="font-size: 12pt;">在</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">查询语句中用</span></strong><strong><span style="font-size: 12pt;">&rdquo;?&rdquo;</span></strong><strong><span style="font-size: 12pt;">来定义参数位置，形式如下：</span></strong></div>
<div style="margin-left: 218.65pt; text-indent: -200.7pt;"><strong><span style="font-size: 12pt;">Query query=session.createQuery(&ldquo;from User user where user.name=? and user.age =? &rdquo;);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">&nbsp;query.setString(0,name);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">&nbsp;query.setInteger(1,age);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt;">同样使用</span></strong><strong><span style="font-size: 12pt;">setXXX()</span></strong><strong><span style="font-size: 12pt;">方法设定绑定参数，只不过这时</span></strong><strong><span style="font-size: 12pt;">setXXX()</span></strong><strong><span style="font-size: 12pt;">方法的第一个参数代表邦定参数在</span></strong><strong><span style="font-size: 12pt;">HQL</span></strong><strong><span style="font-size: 12pt;">语句中出现的位置编号（由</span></strong><strong><span style="font-size: 12pt;">0</span></strong><strong><span style="font-size: 12pt;">开始编号），第二个参数仍然代表参数实际值。</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: red;">注：在实际开发中，提倡使用按名称邦定命名参数，因为这不但可以提供非常好的程序可读性，而且也提高了程序的易维护性，因为当查询参数的位置发生改变时，按名称邦定名参数的方式中是不需要调整程序代码的。</span></strong></div>
<div style="margin-left: 54pt; text-indent: -36pt;"><strong><span style="font-size: 12pt; color: black;">C、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="font-size: 12pt; color: black;">setParameter()</span></strong><strong><span style="font-size: 12pt; color: black;">方法：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">&nbsp;</span></strong><strong><span style="font-size: 12pt; color: black;">在</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate</span></strong><strong><span style="font-size: 12pt; color: black;">的</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">查询中可以通过</span></strong><strong><span style="font-size: 12pt; color: black;">setParameter()</span></strong><strong><span style="font-size: 12pt; color: black;">方法邦定任意类型的参数，如下代码：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">&nbsp;String hql=&rdquo;from User user where user.name=:customername &rdquo;;</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">&nbsp;Query query=session.createQuery(hql);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">&nbsp;query.setParameter(&ldquo;customername&rdquo;,name,Hibernate.STRING);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">&nbsp;</span></strong><strong><span style="font-size: 12pt; color: black;">如上面代码所示，</span></strong><strong><span style="font-size: 12pt; color: black;">setParameter()</span></strong><strong><span style="font-size: 12pt; color: black;">方法包含三个参数，分别是命名参数名称，命名参数实际值，以及命名参数映射类型。对于某些参数类型</span></strong><strong><span style="font-size: 12pt; color: black;">setParameter()</span></strong><strong><span style="font-size: 12pt; color: black;">方法可以更具参数值的</span></strong><strong><span style="font-size: 12pt; color: black;">Java</span></strong><strong><span style="font-size: 12pt; color: black;">类型，猜测出对应的映射类型，因此这时不需要显示写出映射类型，像上面的例子，可以直接这样写：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">query.setParameter(&ldquo;customername&rdquo;,name);</span></strong><strong><span style="font-size: 12pt; color: black;">但是对于一些类型就必须写明映射类型，比如</span></strong><strong><span style="font-size: 12pt; color: black;">java.util.Date</span></strong><strong><span style="font-size: 12pt; color: black;">类型，因为它会对应</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate</span></strong><strong><span style="font-size: 12pt; color: black;">的多种映射类型，比如</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate.DATA</span></strong><strong><span style="font-size: 12pt; color: black;">或者</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate.TIMESTAMP</span></strong><strong><span style="font-size: 12pt; color: black;">。</span></strong></div>
<div style="margin-left: 54pt; text-indent: -36pt;"><strong><span style="font-size: 12pt; color: black;">D、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="font-size: 12pt; color: black;">setProperties()</span></strong><strong><span style="font-size: 12pt; color: black;">方法：</span></strong></div>
<div style="margin-left: 17.95pt; text-indent: 24.1pt;"><strong><span style="font-size: 12pt; color: black;">在</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate</span></strong><strong><span style="font-size: 12pt; color: black;">中可以使用</span></strong><strong><span style="font-size: 12pt; color: black;">setProperties()</span></strong><strong><span style="font-size: 12pt; color: black;">方法，将命名参数与一个对象的属性值绑定在一起，如下程序代码：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">Customer customer=new Customer();</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">customer.setName(&ldquo;pansl&rdquo;);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">customer.setAge(80);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">Query query=session.createQuery(&ldquo;from Customer c where c.name=:name and c.age=:age &rdquo;);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">query.setProperties(customer);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">setProperties()</span></strong><strong><span style="font-size: 12pt; color: black;">方法会自动将</span></strong><strong><span style="font-size: 12pt; color: black;">customer</span></strong><strong><span style="font-size: 12pt; color: black;">对象实例的属性值匹配到命名参数上，但是要求命名参数名称必须要与实体对象相应的属性同名。</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">这里还有一个特殊的</span></strong><strong><span style="font-size: 12pt; color: black;">setEntity()</span></strong><strong><span style="font-size: 12pt; color: black;">方法，它会把命名参数与一个持久化对象相关联，如下面代码所示：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">Customer customer=(Customer)session.load(Customer.class,&rdquo;1&rdquo;);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">Query query=session.createQuery(&ldquo;from Order order where order.customer=:customer &rdquo;);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">query. setProperties(&ldquo;customer&rdquo;,customer);</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">List list=query.list();</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">上面的代码会生成类似如下的</span></strong><strong><span style="font-size: 12pt; color: black;">SQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">Select * from order where customer_ID=&rsquo;1&rsquo;;</span></strong></div>
<div style="margin-left: 54pt; text-indent: -36pt;"><strong><span style="font-size: 12pt; color: black;">E、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="font-size: 12pt; color: black;">使用绑定参数的优势：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">&nbsp;&nbsp; </span></strong><strong><span style="font-size: 12pt; color: black;">我们为什么要使用绑定命名参数？任何一个事物的存在都是有其价值的，具体到绑定参数对于</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">查询来说，主要有以下两个主要优势：</span></strong></div>
<div style="margin-left: 42pt; text-indent: -24pt;"><strong><span style="font-size: 12pt; color: black;">①、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="font-size: 12pt; color: black;">可以利用数据库实施性能优化，因为对</span></strong><strong><span style="font-size: 12pt; color: black;">Hibernate</span></strong><strong><span style="font-size: 12pt; color: black;">来说在底层使用的是</span></strong><strong><span style="font-size: 12pt; color: black;">PrepareStatement</span></strong><strong><span style="font-size: 12pt; color: black;">来完成查询，因此对于语法相同参数不同的</span></strong><strong><span style="font-size: 12pt; color: black;">SQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句，可以充分利用预编译</span></strong><strong><span style="font-size: 12pt; color: black;">SQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句缓存，从而提升查询效率。</span></strong></div>
<div style="margin-left: 42pt; text-indent: -24pt;"><strong><span style="font-size: 12pt; color: black;">②、<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="font-size: 12pt; color: black;">可以防止</span></strong><strong><span style="font-size: 12pt; color: black;">SQL Injection</span></strong><strong><span style="font-size: 12pt; color: black;">安全漏洞的产生：</span></strong></div>
<div style="margin-left: 17.95pt; text-indent: 24.1pt;"><strong><span style="font-size: 12pt; color: black;">SQL Injection</span></strong><strong><span style="font-size: 12pt; color: black;">是一种专门针对</span></strong><strong><span style="font-size: 12pt; color: black;">SQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句拼装的攻击方式，比如对于我们常见的用户登录，在登录界面上，用户输入用户名和口令，这时登录验证程序可能会生成如下的</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">&ldquo;from User user where user.name=&rsquo;&rdquo;+name+&rdquo;&rsquo; and user.password=&rsquo;&rdquo;+password+&rdquo;&rsquo; &rdquo;</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">这个</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句从逻辑上来说是没有任何问题的，这个登录验证功能在一般情况下也是会正确完成的，但是如果在登录时在用户名中输入</span></strong><strong><span style="font-size: 12pt; color: black;">&rdquo;zhaoxin or &lsquo;x&rsquo;=&rsquo;x&rdquo;,</span></strong><strong><span style="font-size: 12pt; color: black;">这时如果使用简单的</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句的字符串拼装，就会生成如下的</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">&ldquo;from User user where user.name=&rsquo;zhaoxin&rsquo; or &lsquo;x&rsquo;=&rsquo;x&rsquo; and user.password=&rsquo;admin&rsquo; &rdquo;;</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">显然这条</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句的</span></strong><strong><span style="font-size: 12pt; color: black;">where</span></strong><strong><span style="font-size: 12pt; color: black;">字句将会永远为真，而使用户口令的作用失去意义，这就是</span></strong><strong><span style="font-size: 12pt; color: black;">SQL Injection</span></strong><strong><span style="font-size: 12pt; color: black;">攻击的基本原理。</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">&nbsp;&nbsp;&nbsp;</span></strong><strong><span style="font-size: 12pt; color: black;">而使用绑定参数方式，就可以妥善处理这问题</span></strong><strong><span style="font-size: 12pt; color: black;">,</span></strong><strong><span style="font-size: 12pt; color: black;">当使用绑定参数时，会得到下面的</span></strong><strong><span style="font-size: 12pt; color: black;">HQL</span></strong><strong><span style="font-size: 12pt; color: black;">语句：</span></strong></div>
<div style="margin-left: 18pt;"><strong><span style="font-size: 12pt; color: black;">from User user where user.name=&rsquo;&rsquo;zhaoxin&rsquo;&rsquo; or &lsquo;&rsquo;x=&rsquo;&rsquo;x&rsquo;&rsquo; &lsquo; and user.password=&rsquo;admin&rsquo;;</span></strong><strong><span style="font-size: 12pt; color: black;">由此可见使用绑定参数会将用户名中输入的单引号解析成字符串（如果想在字符串中包含单引号，应使用重复单引号形式），所以参数绑定能够有效防止</span></strong><strong><span style="font-size: 12pt; color: black;">SQL Injection</span></strong><strong><span style="font-size: 12pt; color: black;">安全漏洞。</span></strong></div>
&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/124923#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><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 18 Sep 2007 11:22:58 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/124923</link>
        <guid>http://wlcome998.javaeye.com/blog/124923</guid>
      </item>
      <item>
        <title>求助HQL的DFA</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/112937" style="color:red;">http://wlcome998.javaeye.com/blog/112937</a>&nbsp;
          发表时间: 2007年08月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>最近想画个识别HQL语言的有限自动机来，</p>
<p>初步将输入的字符流分为三类：</p>
<p>HQL保留字：如from、 where</p>
<p>符号：如 =、&lt;&gt;、！=等</p>
<p>数字或者字母。</p>
<p>先想以from table where a&gt;5为例，来设计能识别类似字符流的DFA</p>
<p>但苦于没什么参考资料，各位高手能指点下或者或提供类似的资料吗？谢谢了</p>
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/112937#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><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><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 16 Aug 2007 10:41:57 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/112937</link>
        <guid>http://wlcome998.javaeye.com/blog/112937</guid>
      </item>
      <item>
        <title>疑问：关于ANTLR判断的结束符</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/102485" style="color:red;">http://wlcome998.javaeye.com/blog/102485</a>&nbsp;
          发表时间: 2007年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          本人最近在看Hibernate源代码，也顺便研究了ANTLR这一应用在Hibernate中对HQL到SQL进行转换的文法分析器。<br />
现有一些疑问列举如下，希望高手赐教：<br />
本人自己写了个expr.g文件，工作平台 eclipse+Antlr studio插件 ANTLR2.7.6<br />
class ExprParser extends Parser;<br />
options{<br />
&nbsp;&nbsp;&nbsp; buildAST=true;<br />
}<br />
expr: bexpr ;<br />
bexpr: mexpr((PLUS^|MINUS^) mexpr)*;<br />
mexpr<br />
&nbsp;&nbsp;&nbsp; :&nbsp; atom(STAR^ atom)*<br />
&nbsp;&nbsp;&nbsp; ;<br />
<br />
atom:&nbsp; INT<br />
&nbsp;&nbsp;&nbsp; | LPAREN! expr RPAREN!<br />
&nbsp;&nbsp;&nbsp; ;<br />
<br />
class ExprLexer extends Lexer;<br />
<br />
options{<br />
&nbsp;&nbsp;&nbsp; k=2;<br />
&nbsp;&nbsp;&nbsp; charVocabulary='\u0000'..'\u007F';<br />
}<br />
<br />
LPAREN&nbsp; : '(';<br />
RPAREN&nbsp; : ')';<br />
PLUS&nbsp;&nbsp;&nbsp; : '+';<br />
MINUS&nbsp;&nbsp; : '-';<br />
STAR&nbsp;&nbsp;&nbsp; : '*';<br />
INT&nbsp;&nbsp;&nbsp;&nbsp; : ('0'..'9')+;<br />
WS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : (' '<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | '\t'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | '\r' '\n' { newline(); }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | '\n'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { newline(); }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { $setType(Token.SKIP); }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;<br />
<br />
java文件<br />
public static void main(String[] args) throws Exception, TokenStreamException {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println(&quot;OK&quot;);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ExprLexer lexer = new ExprLexer(System.in);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ExprParser parser= new ExprParser(lexer);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; parser.expr();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; AST t =parser.getAST();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println(t.toStringTree());<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
以上表达式分要是做词法分析，并转换成AST树<br />
但本人输入1+2或者2+2*2任何表达式 按回车 均无任何反应， 感觉ANTLR并没认为回车是输入的结束，想问下ANTLR中默认的判断输入的结束符是什么？<br />
<br />
好像expr: bexpr ;改成expr: bexpr SEMI; 并在Lexer中添加SEMI&nbsp;&nbsp;&nbsp; :';';，可以实现在Antl强制定义分号为结束符；但不知道如果不加SEMI，ANTLR如何判断输入结束！！
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/102485#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><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><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 18 Jul 2007 17:46:39 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/102485</link>
        <guid>http://wlcome998.javaeye.com/blog/102485</guid>
      </item>
      <item>
        <title>关于Hibernate常用的接口和使用流程</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/95553" style="color:red;">http://wlcome998.javaeye.com/blog/95553</a>&nbsp;
          发表时间: 2007年06月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p class="MsoNormal" style="text-indent: 21pt;"><span lang="EN-US" style="color: red;"><br />
Configuration </span><span style="font-family: 宋体; color: red;">接口</span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span lang="EN-US">Configuration</span><span style="font-family: 宋体;">接口的作用是对</span><span lang="EN-US">Hibernate</span><span style="font-family: 宋体;">进行配置，以及对它进行启动。在</span><span lang="EN-US">Hibernate</span><span style="font-family: 宋体;">的启动过程中，</span><span lang="EN-US">Configuration</span><span style="font-family: 宋体;">类的实例首先定位映射文档的位置，读取这些配置，然后创建一个</span><span lang="EN-US">SessionFactory</span><span lang="EN-US" style="color: red;">对象。<br />
SessionFactory </span><span style="font-family: 宋体; color: red;">接口</span><span lang="EN-US" style="color: red;"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">　　这里用到了一个设计模式――工厂模式，用户程序从工厂类</span><span lang="EN-US">SessionFactory</span><span style="font-family: 宋体;">中取得</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">的实例。</span><span lang="EN-US" style="font-size: 10.5pt; font-family: &quot;Times New Roman&quot;;">SessionFactory</span><span style="font-family: 宋体;">并不是轻量级的，一个项目通常只需要一个</span><span lang="EN-US"> SessionFactory</span><span style="font-family: 宋体;">就够了，但是当你的项目要操作多个数据库时，那你必须为每个数据库指定一个</span><span lang="EN-US">SessionFactory</span><span lang="EN-US">。<br />
SessionFactory</span><span style="font-family: 宋体;">在</span><span lang="EN-US">Hibernate</span><span style="font-family: 宋体;">中实际起到了一个缓冲区的作用，它缓冲了</span><span lang="EN-US">Hibernate</span><span style="font-family: 宋体;">自动生成的</span><span lang="EN-US">SQL</span><span style="font-family: 宋体;">语句和一些其它的映射数据，还缓冲了一些将来有可能重复利用的数据。</span></p>
<p class="MsoNormal">  </p>
<p class="MsoNormal"><span style="">&nbsp;</span><span lang="EN-US" style="color: red;">Session</span><span style="font-family: 宋体; color: red;">接口</span><span lang="EN-US" style="color: red;"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">　　</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">接口对于</span><span lang="EN-US">Hibernate </span><span style="font-family: 宋体;">开发人员来说是一个最重要的接口。然而在</span><span lang="EN-US">Hibernate</span><span style="font-family: 宋体;">中，实例化的</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">是一个轻量级的类，创建和销毁它都不会占用很多资源。这在实际项目中确实很重要，因为在客户程序中，可能会不断地创建以及销毁</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">对象，如果</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">的开销太大，会给系统带来不良影响。但值得注意的是</span><span lang="EN-US"> Session</span><span style="font-family: 宋体;">对象是非线程安全的，因此在你的设计中，最好是一个线程只创建一个</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">对象。</span></p>
<p class="MsoNormal">  </p>
<p class="MsoNormal" style="text-indent: 21pt;"><span lang="EN-US">Hibernate</span><span style="font-family: 宋体;">使用</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">来存取，它是持久化管理器接口，代表与数据库之间的一次操作。然而为了操作持久化数据，首先要获得</span><span lang="EN-US">SessionFactory</span><span style="font-family: 宋体;">对象，</span><span lang="EN-US">SessionFactory</span><span style="font-family: 宋体;">负责一个数据库，是</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">的工厂，对于一个</span><span lang="EN-US">XML</span><span style="font-family: 宋体;">配置文件，</span><span lang="EN-US">SessionFactory</span><span style="font-family: 宋体;">对象</span><span lang="EN-US">Configuration</span><span style="font-family: 宋体;">对象负责创建。这里的</span><span lang="EN-US">net.sf.hibernate.cfg.Configuration</span><span style="font-family: 宋体;">的一个实例代表了应用程序中所有的</span><span lang="EN-US">Java</span><span style="font-family: 宋体;">类到关系数据库的映射的集合，这些映射是从一些</span><span lang="EN-US">XML</span><span style="font-family: 宋体;">映射文件中编译得到的。可以得到一个</span><span lang="EN-US">Configuration</span><span style="font-family: 宋体;">的实例，直接实例化即可，当所有的映射都被</span><span lang="EN-US">Configuration</span><span style="font-family: 宋体;">解析之后，应用程序为了得到</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">实例，必须先得到它的工厂，这些工厂应该是应用程序的所有线程所共享的。当然</span><span lang="EN-US">Hibernate</span><span style="font-family: 宋体;">并不禁止程序实例化多个</span><span lang="EN-US">SessionFactory</span><span style="font-family: 宋体;">，这在使用不止一个数据库时候就很有用。</span></p>
<p class="MsoNormal"><span lang="EN-US" style="color: red;">Transaction </span><span style="font-family: 宋体; color: red;">接口</span><span lang="EN-US" style="color: red;"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">　　</span><span lang="EN-US">Transaction</span><span style="font-family: 宋体;">接口是一个可选的</span><span lang="EN-US">API</span><span style="font-family: 宋体;">，你可以选择不使用这个接口，取而代之的是</span><span lang="EN-US">Hibernate</span><span style="font-family: 宋体;">的设计者自己写的底层事务处理代码。</span><span lang="EN-US"> Transaction</span><span style="font-family: 宋体;">接口是对实际事务实现的一个抽象，这些实现包括</span><span lang="EN-US">JDBC</span><span style="font-family: 宋体;">的事务、</span><span lang="EN-US">JTA</span><span style="font-family: 宋体;">中的</span><span lang="EN-US">UserTransaction</span><span style="font-family: 宋体;">、甚至可以是</span><span lang="EN-US">CORBA </span><span style="font-family: 宋体;">事务。之所以这样设计是能让开发者能够使用一个统一事务的操作界面，使得自己的项目可以在不同的环境和容器之间方便地移值。</span></p>
<p class="MsoNormal"><span lang="EN-US" style="color: red;">Query</span><span style="font-family: 宋体; color: red;">和</span><span lang="EN-US" style="color: red;">Criteria</span><span style="font-family: 宋体; color: red;">接口</span><span lang="EN-US" style="color: red;"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">　　</span><span lang="EN-US">Query</span><span style="font-family: 宋体;">接口让你方便地对数据库及持久对象进行查询，它可以有两种表达方式：</span><span lang="EN-US">HQL</span><span style="font-family: 宋体;">语言或本地数据库的</span><span lang="EN-US">SQL</span><span style="font-family: 宋体;">语句。</span><span lang="EN-US">Query</span><span style="font-family: 宋体;">经常被用来绑定查询参数、限制查询记录数量，并最终执行查询操作。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">　　</span><span lang="EN-US">Criteria</span><span style="font-family: 宋体;">接口与</span><span lang="EN-US">Query</span><span style="font-family: 宋体;">接口非常类似，它允许你创建并执行面向对象的标准化查询。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">　　值得注意的是</span><span lang="EN-US">Query</span><span style="font-family: 宋体;">接口也是轻量级的，它不能在</span><span lang="EN-US">Session</span><span style="font-family: 宋体;">之外使用。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体; color: red;"></span><span lang="EN-US" style="color: red;">Callback </span><span style="font-family: 宋体; color: red;">接口</span><span lang="EN-US" style="color: red;"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">当一些有用的事件发生时――例如持久对象的载入、存储、删除时，</span><span lang="EN-US">Callback</span><span style="font-family: 宋体;">接口会通知</span><span lang="EN-US">Hibernate</span><span style="font-family: 宋体;">去接收一个通知消息。一般而言，</span><span lang="EN-US">Callback</span><span style="font-family: 宋体;">接口在用户程序中并不是必须的，但你要在你的项目中创建审计日志时，你可能会用到它。</span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;"><br />
</span></p>
          <br/>
          <span style="color:red;">
            <a href="http://wlcome998.javaeye.com/blog/95553#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</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>Fri, 29 Jun 2007 15:36:19 +0800</pubDate>
        <link>http://wlcome998.javaeye.com/blog/95553</link>
        <guid>http://wlcome998.javaeye.com/blog/95553</guid>
      </item>
      <item>
        <title>ANTLR一个编译简单的两数相加的例子</title>
        <author>wlcome998</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wlcome998.javaeye.com">wlcome998</a>&nbsp;
          链接：<a href="http://wlcome998.javaeye.com/blog/89480" style="color:red;">http://wlcome998.javaeye.com/blog/89480</a>&nbsp;
          发表时间: 2007年06月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p class="MsoNormal"><span style="font-family: 宋体;">如同程序设计语言入门大多采用</span><span lang="EN-US">&ldquo;Hello World&rdquo;</span><span style="font-family: 宋体;">一样，编译领域的入门往往选择计算器。一个只能计算两个数相加的计算器，也就是说，它可以计算</span><span lang="EN-US">&ldquo;1+1&rdquo;</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">编译过程分两步走：</span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size: 15pt; color: red;">1 </span><span style="font-size: 15pt; font-family: 宋体; color: red;">先要能识别</span><span lang="EN-US" style="font-size: 15pt; color: red;">1+1</span><span style="font-size: 15pt; font-family: 宋体; color: red;">这样的格式</span><span lang="EN-US" style="font-size: 15pt; color: red;"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">检查输入的正确性，只有对正确的输入进行计算才是有意义的。如同写文章有形式和内容之分，这里的检查也要细分一下，这个过程叫做<span style="color: red;">词法分析</span>。在我们的计算器中，我们只接受整数和加号，其它的一概不理。这里我们说的是</span><span lang="EN-US">&ldquo;</span><span style="font-family: 宋体;">整数</span><span lang="EN-US">&rdquo;</span><span style="font-family: 宋体;">，而非</span><span lang="EN-US"> &ldquo;1&rdquo;</span><span style="font-family: 宋体;">、</span><span lang="EN-US">&ldquo;2&rdquo;&hellip;&hellip;</span><span style="font-family: 宋体;">，对我们来说，它们代表着同一类的东西，编译原理称为叫做</span><span lang="EN-US">token</span></p>
<p><strong><span style="font-family: 宋体;">编写语法文件<span lang="EN-US"><o:p></o:p></span></span></strong></p>
<p><span style="font-size: 10.5pt;">制订好自己的语言规则之后，我们需要以</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Antlr</span><span style="font-size: 10.5pt;">的语言把它描述出来。</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><br />
</span><span style="font-size: 10.5pt;">下面便是以</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Antlr</span><span style="font-size: 10.5pt;">的语言描述的语法：</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><br />
class CaculatorParser extends Parser;<br />
expr:&nbsp;&nbsp; INT PLUS INT; <o:p></o:p></span></p>
<p><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">class CaculatorLexer extends Lexer;<br />
PLUS&nbsp; : '+' ;<br />
INT&nbsp;&nbsp; : ('0'..'9')+ ;<o:p></o:p></span></p>
<p><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Antlr</span><span style="font-size: 10.5pt;">的语法文件通常会保存在一个</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">&ldquo;.g&rdquo;</span><span style="font-size: 10.5pt;">的文件中，我们的语法文件叫做</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">&ldquo;caculator.g&rdquo;</span><span style="font-size: 10.5pt;">。</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><o:p></o:p></span></p>
<p><span style="font-size: 10.5pt;">先来看看</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Lexer</span><span style="font-size: 10.5pt;">部分，它便是我们前面所说的词法分析器。首先声明自己的</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Lexer</span><span style="font-size: 10.5pt;">：</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><br />
class CaculatorLexer extends Lexer;<br />
</span><span style="font-size: 10.5pt;">这句话有两个作用，其一，为生成代码中的词法分析器定义名字，其二，告诉</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Antlr</span><span style="font-size: 10.5pt;">，我要定义词法规则了。既然说到词法规则，紧接着我们就定义了两条词法规则：</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><br />
PLUS&nbsp; : '+' ;<br />
INT&nbsp;&nbsp; : ('0'..'9')+ ;<br />
</span><span style="font-size: 10.5pt;">这里的规则很容易看懂：</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><br />
* PLUS</span><span style="font-size: 10.5pt;">定义的</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">token</span><span style="font-size: 10.5pt;">，就是一个单一的</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">&ldquo;+&rdquo;<br />
* INT</span><span style="font-size: 10.5pt;">定义的</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">token</span><span style="font-size: 10.5pt;">，由从</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">'0'</span><span style="font-size: 10.5pt;">到</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">'9'</span><span style="font-size: 10.5pt;">之间任意的数字组成，后面的加号表示它是可以重复一次到多次</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">定义好</span><span lang="EN-US">Lexer</span><span style="font-family: 宋体;">之后，便轮到</span><span lang="EN-US">Parser</span><span style="font-family: 宋体;">了：</span><span lang="EN-US"><br />
class CaculatorParser extends Parser;<br />
</span><span style="font-family: 宋体;">它的作用同</span><span lang="EN-US">Lexer</span><span style="font-family: 宋体;">的定义一样，之后是语法规则：</span><span lang="EN-US"><br />
expr:&nbsp;&nbsp; INT PLUS INT;</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p><strong><span style="font-family: 宋体;">编译语法文件<span lang="EN-US"><o:p></o:p></span></span></strong></p>
<p><span style="font-size: 10.5pt;">使用</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Antlr</span><span style="font-size: 10.5pt;">提供工具对我们的语法文件进行编译，不同</span><span new="" times="" roman="" style="font-size: 10.5pt;"> </span><span style="font-size: 10.5pt;">于日常的编译器输出可执行文件，这里的输出是程序语言的源文件。</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Antlr</span><span style="font-size: 10.5pt;">缺省目标语言是</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Java</span><span style="font-size: 10.5pt;">语言，它也可以支持</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">C++</span><span style="font-size: 10.5pt;">和</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">C#</span><span style="font-size: 10.5pt;">语言。</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><o:p></o:p></span></p>
<p><span style="font-size: 10.5pt;">将</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">antlr.jar</span><span style="font-size: 10.5pt;">加到</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">classpath</span><span style="font-size: 10.5pt;">中，然后把语法文件的名称作为参数传给语法编译器：</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><br />
java antlr.Tool caculator.g<o:p></o:p></span></p>
<p><span style="font-size: 10.5pt;">在确保命令正确执行，且语法文件编写正确的情况下，</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;">Antlr</span><span style="font-size: 10.5pt;">为我们生成了几个文件：</span><span new="" times="" lang="EN-US" roman="" style="font-size: 10.5pt;"><br />
CaculatorLexer.java<br />
CaculatorLexerTokenTypes.java<br />
CaculatorLexerTokenTypes.txt<br />
CaculatorParser.java<br />
CaculatorParserTokenTypes.java<br />
CaculatorParserTokenTypes.txt<o:p></o:p></span></p>
<p><span style="font-size: 10.5pt;">这里主要关心的是</span><span new="" time