﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-maple_stephen-随笔分类-经典转贴</title><link>http://www.blogjava.net/SkyWinder/category/13635.html</link><description>Just try to find my memorize...</description><language>zh-cn</language><lastBuildDate>Mon, 01 Oct 2007 19:01:04 GMT</lastBuildDate><pubDate>Mon, 01 Oct 2007 19:01:04 GMT</pubDate><ttl>60</ttl><item><title>T—SQL命令汇总</title><link>http://www.blogjava.net/SkyWinder/archive/2007/09/30/149866.html</link><dc:creator>枫中玎玲</dc:creator><author>枫中玎玲</author><pubDate>Sun, 30 Sep 2007 05:13:00 GMT</pubDate><guid>http://www.blogjava.net/SkyWinder/archive/2007/09/30/149866.html</guid><wfw:comment>http://www.blogjava.net/SkyWinder/comments/149866.html</wfw:comment><comments>http://www.blogjava.net/SkyWinder/archive/2007/09/30/149866.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/SkyWinder/comments/commentRss/149866.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/SkyWinder/services/trackbacks/149866.html</trackback:ping><description><![CDATA[T—SQL命令汇总<br />
<br />
执行操作 T—SQL语句 <br />
<br />
创建数据库 CREATE&nbsp;&nbsp;DATABASE&nbsp;&nbsp;数据库名 <br />
<br />
删除数据库 DROP&nbsp;&nbsp;&nbsp;&nbsp;DATABASE&nbsp;&nbsp;数据库名 <br />
<br />
创建表 CREATE&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;表名 <br />
<br />
删除表 DROP&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;表名 <br />
<br />
修改表的字段类型 ALTER&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;表名&nbsp;ALTER&nbsp;&nbsp;COLUMN&nbsp;&nbsp;字段名&nbsp;&nbsp;数据类型 <br />
<br />
向表中添加新的字段 ALTER&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;表名&nbsp;ADD&nbsp;&nbsp;&nbsp;&nbsp;字段名&nbsp;&nbsp;&nbsp;&nbsp;数据类型 <br />
<br />
删除表中原有字段 ALTER&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;表名&nbsp;DROP&nbsp;&nbsp;&nbsp;COLUMN&nbsp;&nbsp;字段名 <br />
<br />
向已有表中添加主键 ALTER&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;表名&nbsp;ADD&nbsp;&nbsp;CONSTRAINT&nbsp;约束名&nbsp;PRIMARY&nbsp;KEY&nbsp;(主键字段名) <br />
<br />
向已有表中添加外键 ALTER&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;表名&nbsp;ADD&nbsp;&nbsp;CONSTRAINT&nbsp;约束名&nbsp;FOREIGN&nbsp;KEY&nbsp;(外键字段<br />
名)&nbsp;REFERENCES&nbsp;&nbsp;主键表名（主键字段名） <br />
<br />
删除表中已有约束：alter table 表名 drop constraint 约束名<br />
<br />
向已有表中添加默认值 ALTER&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;表名&nbsp;ADD&nbsp;&nbsp;CONSTRAINT&nbsp;约束名&nbsp;DEFAULT&nbsp;默认值&nbsp;FOR&nbsp;&nbsp;&nbsp;添加默认值的字段名 <br />
<br />
向已有表中添加检查约束 ALTER&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;表名&nbsp;ADD&nbsp;&nbsp;CONSTRAINT&nbsp;约束名_CHECK&nbsp;&nbsp;CHECEK&nbsp;(检查约束表达式) <br />
<br />
向已有表中添加惟一性 ALTER&nbsp;&nbsp;TABLE&nbsp;&nbsp;&nbsp;&nbsp;表名&nbsp;ADD&nbsp;&nbsp;CONSTRAINT&nbsp;约束名&nbsp;UNIQUE（添加惟一性的字段名）&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
向表中添加数据 INSERT&nbsp;INTO&nbsp;表名&nbsp;&nbsp;valueS&nbsp;(向表中添加的记录) <br />
<br />
把表A中数据拷贝到表B中 INSERT&nbsp;INTO&nbsp;表B名&nbsp;&nbsp;SELECT&nbsp;字段名&nbsp;FROM&nbsp;表A名 <br />
<br />
更新表中所有记录数据 UPDATE&nbsp;表名&nbsp;SET&nbsp;&nbsp;数据更新表达式 <br />
<br />
更新一个或部分记录 UPDATE&nbsp;表名&nbsp;SET&nbsp;&nbsp;数据更新表达式&nbsp;WHERE&nbsp;选择数据的条件 <br />
<br />
删除表中全部记录 DELETE&nbsp;&nbsp;FROM&nbsp;&nbsp;表名&nbsp;TRUNCATE&nbsp;TABLE&nbsp;表名 <br />
<br />
删除部分记录 DELETE&nbsp;&nbsp;FROM&nbsp;&nbsp;表名&nbsp;&nbsp;WHERE&nbsp;&nbsp;记录选择条件 <br />
<br />
按条件查询表中记录&nbsp; SELECT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名&nbsp;WHERE&nbsp;查询条件 <br />
<br />
使用ORDER&nbsp;BY子句 SELECT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名&nbsp;ORDER&nbsp;BY&nbsp;排序字段名&nbsp;SELECT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名&nbsp;ORDER&nbsp;BY&nbsp;排序字段名&nbsp;DESC <br />
<br />
使用AS子句 SELECT&nbsp;字段名&nbsp;AS&nbsp;结果显示时的字段名&nbsp;&nbsp;FROM&nbsp;&nbsp;表名 <br />
<br />
使用TOP子句 SELECT&nbsp;&nbsp;TOP&nbsp;&nbsp;N&nbsp;字段名&nbsp;FROM&nbsp;表名&nbsp;SELECT&nbsp;&nbsp;TOP&nbsp;&nbsp;N&nbsp;&nbsp;PERCENT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名 <br />
<br />
SUM函数 SELECT&nbsp;&nbsp;SUM&nbsp;(字段名)&nbsp;&nbsp;FROM&nbsp;表名 <br />
<br />
AVG函数 SELECT&nbsp;&nbsp;AVG&nbsp;(字段名)&nbsp;&nbsp;FROM&nbsp;表名 <br />
<br />
COUNT函数 SELECT&nbsp;&nbsp;COUNT&nbsp;(字段名)&nbsp;&nbsp;FROM&nbsp;表名 <br />
<br />
MAX函数 SELECT&nbsp;&nbsp;MAX&nbsp;(字段名)&nbsp;&nbsp;FROM&nbsp;表名 <br />
<br />
MIN函数 SELECT&nbsp;&nbsp;MIN&nbsp;(字段名)&nbsp;&nbsp;FROM&nbsp;表名 <br />
<br />
使用GROUP&nbsp;BY子句 SELECT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名&nbsp;GROUP&nbsp;BY&nbsp;分组字段名 <br />
<br />
使用HAVING子句 SELECT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名&nbsp;WHERE&nbsp;查询条件&nbsp;GROUP&nbsp;BY&nbsp;分组字段名&nbsp;&nbsp;HAVING&nbsp;分组条件 <br />
LIKE通配符 SELECT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名&nbsp;WHERE&nbsp;字段名&nbsp;LIKE&nbsp;条件 <br />
<br />
IN&nbsp;通配符 SELECT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名&nbsp;WHERE&nbsp;字段名&nbsp;IN&nbsp;&nbsp;(值) <br />
<br />
BETWEEN通配符 SELECT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名&nbsp;WHERE&nbsp;字段名&nbsp;BETWEEN&nbsp;值1&nbsp;AND&nbsp;值2 <br />
<br />
IS&nbsp;NULL&nbsp;通配符 SELECT&nbsp;字段名&nbsp;FROM&nbsp;&nbsp;表名&nbsp;WHERE&nbsp;字段名&nbsp;IS&nbsp;NULL 
<img src ="http://www.blogjava.net/SkyWinder/aggbug/149866.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/SkyWinder/" target="_blank">枫中玎玲</a> 2007-09-30 13:13 <a href="http://www.blogjava.net/SkyWinder/archive/2007/09/30/149866.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sql文件编写规范</title><link>http://www.blogjava.net/SkyWinder/archive/2007/09/30/149863.html</link><dc:creator>枫中玎玲</dc:creator><author>枫中玎玲</author><pubDate>Sun, 30 Sep 2007 05:07:00 GMT</pubDate><guid>http://www.blogjava.net/SkyWinder/archive/2007/09/30/149863.html</guid><wfw:comment>http://www.blogjava.net/SkyWinder/comments/149863.html</wfw:comment><comments>http://www.blogjava.net/SkyWinder/archive/2007/09/30/149863.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/SkyWinder/comments/commentRss/149863.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/SkyWinder/services/trackbacks/149863.html</trackback:ping><description><![CDATA[<p>SQL编写规范</p>
<p>1.书写格式<br />
示例代码：</p>
<p>存储过程SQL文书写格式例<br />
select <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.dealerCode,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; round(sum(c.submitSubletAmountDLR + c.submitPartsAmountDLR + c.submitLaborAmountDLR) / count(*), 2) as avg, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; decode(null, 'x', 'xx', 'CNY') <br />
from ( <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.dealerCode,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.submitSubletAmountDLR, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.submitPartsAmountDLR, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.submitLaborAmountDLR <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from SRV_TWC_F a<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where (to_char(a.ORIGSUBMITTIME, 'yyyy/mm/dd') &gt;= 'Date Range(start)' <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and to_char(a.ORIGSUBMITTIME, 'yyyy/mm/dd') &lt;= 'Date Range(end)'&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and nvl(a.deleteflag, '0') &lt;&gt; '1') <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union all <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.dealerCode,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.submitSubletAmountDLR, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.submitPartsAmountDLR, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.submitLaborAmountDLR <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from SRV_TWCHistory_F b<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where (to_char(b.ORIGSUBMITTIME, 'yyyy/mm/dd') &gt;= 'Date Range(start)' <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and to_char(b.ORIGSUBMITTIME,'yyyy/mm/dd') &lt;= 'Date Range(end)'&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and nvl(b.deleteflag,'0') &lt;&gt; '1')<br />
) c<br />
group by c.dealerCode <br />
order by avg desc;</p>
<p>Java source里的SQL字符串书写格式例<br />
strSQL = "insert into Snd_FinanceHistory_Tb "<br />
&nbsp;&nbsp;&nbsp; + "(DEALERCODE, "<br />
&nbsp;&nbsp;&nbsp; + "REQUESTSEQUECE, "<br />
&nbsp;&nbsp;&nbsp; + "HANDLETIME, "<br />
&nbsp;&nbsp;&nbsp; + "JOBFLAG, "<br />
&nbsp;&nbsp;&nbsp; + "FRAMENO, "<br />
&nbsp;&nbsp;&nbsp; + "INMONEY, "<br />
&nbsp;&nbsp;&nbsp; + "REMAINMONEY, "<br />
&nbsp;&nbsp;&nbsp; + "DELETEFLAG, "<br />
&nbsp;&nbsp;&nbsp; + "UPDATECOUNT, "<br />
&nbsp;&nbsp;&nbsp; + "CREUSER, "<br />
&nbsp;&nbsp;&nbsp; + "CREDATE, "<br />
&nbsp;&nbsp;&nbsp; + "HONORCHECKNO, "<br />
&nbsp;&nbsp;&nbsp; + "SEQ) "<br />
&nbsp;&nbsp;&nbsp; + "values ('" + draftInputDetail.dealerCode + "', "<br />
&nbsp;&nbsp;&nbsp; + "'" + draftInputDetail.requestsequece + "', "<br />
&nbsp;&nbsp;&nbsp; + "sysdate, "<br />
&nbsp;&nbsp;&nbsp; + "'07', "<br />
&nbsp;&nbsp;&nbsp; + "'" + frameNO + "', "<br />
&nbsp;&nbsp;&nbsp; + requestMoney + ", "<br />
&nbsp;&nbsp;&nbsp; + remainMoney + ", "<br />
&nbsp;&nbsp;&nbsp; + "'0', "<br />
&nbsp;&nbsp;&nbsp; + "0, "<br />
&nbsp;&nbsp;&nbsp; + "'" + draftStruct.employeeCode + "', "<br />
&nbsp;&nbsp;&nbsp; + "sysdate, "<br />
&nbsp;&nbsp;&nbsp; + "'" + draftInputDetail.honorCheckNo + "', "<br />
&nbsp;&nbsp;&nbsp; + index + ")";</p>
<p>&nbsp; 1).缩进<br />
&nbsp;&nbsp;&nbsp; 对于存储过程文件，缩进为8个空格<br />
&nbsp;&nbsp;&nbsp; 对于Java source里的SQL字符串，不可有缩进，即每一行字符串不可以空格开头</p>
<p>&nbsp; 2).换行<br />
&nbsp;&nbsp;&nbsp; 1&gt;.Select/From/Where/Order by/Group by等子句必须另其一行写<br />
&nbsp;&nbsp;&nbsp; 2&gt;.Select子句内容如果只有一项，与Select同行写<br />
&nbsp;&nbsp;&nbsp; 3&gt;.Select子句内容如果多于一项，每一项单独占一行，在对应Select的基础上向右缩进8个空格（Java source无缩进）<br />
&nbsp;&nbsp;&nbsp; 4&gt;.From子句内容如果只有一项，与From同行写<br />
&nbsp;&nbsp;&nbsp; 5&gt;.From子句内容如果多于一项，每一项单独占一行，在对应From的基础上向右缩进8个空格（Java source无缩进）<br />
&nbsp;&nbsp;&nbsp; 6&gt;.Where子句的条件如果有多项，每一个条件占一行，以AND开头，且无缩进<br />
&nbsp;&nbsp;&nbsp; 7&gt;.(Update)Set子句内容每一项单独占一行，无缩进<br />
&nbsp;&nbsp;&nbsp; 8&gt;.Insert子句内容每个表字段单独占一行，无缩进；values每一项单独占一行，无缩进<br />
&nbsp;&nbsp;&nbsp; 9&gt;.SQL文中间不允许出现空行<br />
&nbsp;&nbsp;&nbsp; 10&gt;.Java source里单引号必须跟所属的SQL子句处在同一行，连接符（"+"）必须在行首</p>
<p>&nbsp; 3).空格<br />
&nbsp;&nbsp;&nbsp; 1&gt;.SQL内算数运算符、逻辑运算符连接的两个元素之间必须用空格分隔<br />
&nbsp;&nbsp;&nbsp; 2&gt;.逗号之后必须接一个空格<br />
&nbsp;&nbsp;&nbsp; 3&gt;.关键字、保留字和左括号之间必须有一个空格</p>
<p>2.不等于统一使用"&lt;&gt;"<br />
&nbsp; Oracle认为"!="和"&lt;&gt;"是等价的，都代表不等于的意义。为了统一，不等于一律使用"&lt;&gt;"表示</p>
<p>3.使用表的别名<br />
&nbsp; 数据库查询，必须使用表的别名</p>
<p>4.SQL文对表字段扩展的兼容性<br />
&nbsp; 在Java source里使用Select *时，严禁通过getString(1)的形式得到查询结果，必须使用getString("字段名")的形式<br />
&nbsp; 使用Insert时，必须指定插入的字段名，严禁不指定字段名直接插入values</p>
<p>5.减少子查询的使用<br />
&nbsp; 子查询除了可读性差之外，还在一定程度上影响了SQL运行效率<br />
&nbsp; 请尽量减少使用子查询的使用，用其他效率更高、可读性更好的方式替代</p>
<p>6.适当添加索引以提高查询效率<br />
&nbsp; 适当添加索引可以大幅度的提高检索速度<br />
&nbsp; 请参看ORACLE SQL性能优化系列</p>
<p>7.对数据库表操作的特殊要求<br />
&nbsp; 本项目对数据库表的操作还有以下特殊要求：</p>
<p>&nbsp; 1).以逻辑删除替代物理删除<br />
&nbsp;&nbsp;&nbsp; 注意：现在数据库表中数据没有物理删除，只有逻辑删除<br />
&nbsp;&nbsp;&nbsp; 以deleteflag字段作为删除标志，deleteflag='1'代表此记录被逻辑删除，因此在查询数据时必须考虑deleteflag的因素<br />
&nbsp;&nbsp;&nbsp; deleteflag的标准查询条件：NVL(deleteflag, '0') &lt;&gt; '1'</p>
<p>&nbsp; 2).增加记录状态字段<br />
&nbsp;&nbsp;&nbsp; 数据库中的每张表基本都有以下字段：DELETEFLAG、UPDATECOUNT、CREDATE、CREUSER、UPDATETIME、UPDATEUSER<br />
&nbsp;&nbsp;&nbsp; 要注意在对标进行操作时必须考虑以下字段</p>
<p>&nbsp;&nbsp;&nbsp; 插入一条记录时要置DELETEFLAG='0', UPDATECOUNT=0, CREDATE=sysdate, CREUSER=登录User<br />
&nbsp;&nbsp;&nbsp; 查询一条记录时要考虑DELETEFLAG，如果有可能对此记录作更新时还要取得UPDATECOUNT作同步检查<br />
&nbsp;&nbsp;&nbsp; 修改一条记录时要置UPDATETIME=sysdate, UPDATEUSER=登录User, UPDATECOUNT=(UPDATECOUNT+1) mod 1000, <br />
&nbsp;&nbsp;&nbsp; 删除一条记录时要置DELETEFLAG='1'</p>
<p>&nbsp; 3).历史表<br />
&nbsp;&nbsp;&nbsp; 数据库里部分表还存在相应的历史表，比如srv_twc_f和srv_twchistory_f<br />
&nbsp;&nbsp;&nbsp; 在查询数据时除了检索所在表之外，还必须检索相应的历史表，对二者的结果做Union（或Union All）</p>
<p>8.用执行计划分析SQL性能<br />
&nbsp; EXPLAIN PLAN是一个很好的分析SQL语句的工具，它可以在不执行SQL的情况下分析语句<br />
&nbsp; 通过分析，我们就可以知道ORACLE是怎样连接表，使用什么方式扫描表（索引扫描或全表扫描），以及使用到的索引名称</p>
<p>&nbsp; 按照从里到外，从上到下的次序解读分析的结果<br />
&nbsp; EXPLAIN PLAN的分析结果是用缩进的格式排列的，最内部的操作将最先被解读，如果两个操作处于同一层中，带有最小操作号的将首先被执行</p>
<p>&nbsp; 目前许多第三方的工具如PLSQL Developer和TOAD等都提供了极其方便的EXPLAIN PLAN工具<br />
&nbsp; PG需要将自己添加的查询SQL文记入log，然后在EXPLAIN PLAN中进行分析，尽量减少全表扫描</p>
<p><br />
ORACLE SQL性能优化系列</p>
<p>1.选择最有效率的表名顺序(只在基于规则的优化器中有效)<br />
&nbsp;&nbsp; ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名，因此FROM子句中写在最后的表（基础表driving table）将被最先处理<br />
&nbsp;&nbsp; 在FROM子句中包含多个表的情况下，必须选择记录条数最少的表作为基础表<br />
&nbsp;&nbsp; 当ORACLE处理多个表时，会运用排序及合并的方式连接它们<br />
&nbsp;&nbsp; 首先，扫描第一个表（FROM子句中最后的那个表)并对记录进行排序；<br />
&nbsp;&nbsp; 然后扫描第二个表（FROM子句中最后第二个表)；<br />
&nbsp;&nbsp; 最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并<br />
&nbsp;&nbsp; 例如:<br />
&nbsp;&nbsp;&nbsp;&nbsp; 表 TAB1 16,384 条记录<br />
&nbsp;&nbsp;&nbsp;&nbsp; 表 TAB2 5 条记录<br />
&nbsp;&nbsp;&nbsp;&nbsp; 选择TAB2作为基础表 (最好的方法)<br />
&nbsp;&nbsp;&nbsp;&nbsp; select count(*) from tab1,tab2 执行时间0.96秒 <br />
&nbsp;&nbsp;&nbsp;&nbsp; 选择TAB2作为基础表 (不佳的方法)<br />
&nbsp;&nbsp;&nbsp;&nbsp; select count(*) from tab2,tab1 执行时间26.09秒 </p>
<p>&nbsp;&nbsp; 如果有3个以上的表连接查询，那就需要选择交叉表（intersection table）作为基础表，交叉表是指那个被其他表所引用的表<br />
&nbsp;&nbsp; 例如:<br />
&nbsp;&nbsp;&nbsp;&nbsp; EMP表描述了LOCATION表和CATEGORY表的交集<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT * <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM LOCATION L,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CATEGORY C,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EMP E<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE E.EMP_NO BETWEEN 1000 AND 2000<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND E.CAT_NO = C.CAT_NO<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND E.LOCN = L.LOCN</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 将比下列SQL更有效率<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT * <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP E ,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCATION L ,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CATEGORY C<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE E.CAT_NO = C.CAT_NO<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND E.LOCN = L.LOCN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND E.EMP_NO BETWEEN 1000 AND 2000 </p>
<p>2.WHERE子句中的连接顺序<br />
&nbsp; ORACLE采用自下而上的顺序解析WHERE子句<br />
&nbsp; 根据这个原理，表之间的连接必须写在其他WHERE条件之前，那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾<br />
&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp;&nbsp; (低效,执行时间156.3秒)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT *<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP E<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE SAL &gt; 50000<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND JOB = 'MANAGER'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND 25 &lt; (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; (高效,执行时间10.6秒)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT *<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP E<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE 25 &lt; (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND SAL &gt; 50000<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND JOB = 'MANAGER';</p>
<p>3.SELECT子句中避免使用'*'<br />
&nbsp; 当你想在SELECT子句中列出所有的COLUMN时，使用动态SQL列引用'*'是一个方便的方法，不幸的是，这是一个非常低效的方法<br />
&nbsp; 实际上，ORACLE在解析的过程中，会将'*'依次转换成所有的列名<br />
&nbsp; 这个工作是通过查询数据字典完成的，这意味着将耗费更多的时间</p>
<p>4.减少访问数据库的次数 <br />
&nbsp; 当执行每条SQL语句时，ORACLE在内部执行了许多工作：解析SQL语句，估算索引的利用率，绑定变量，读数据块等等<br />
&nbsp; 由此可见，减少访问数据库的次数，就能实际上减少ORACLE的工作量<br />
&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp; 以下有三种方法可以检索出雇员号等于0342或0291的职员<br />
&nbsp;&nbsp;&nbsp; 方法1 (最低效)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT EMP_NAME, SALARY, GRADE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE EMP_NO = 342;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT EMP_NAME, SALARY, GRADE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE EMP_NO = 291;</p>
<p>&nbsp;&nbsp;&nbsp; 方法2 (次低效)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECLARE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CURSOR C1 (E_NO NUMBER) IS<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT EMP_NAME,SALARY,GRADE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE EMP_NO = E_NO;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BEGIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OPEN C1(342);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FETCH C1 INTO &#8230;,&#8230;,&#8230;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OPEN C1(291);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FETCH C1 INTO &#8230;,&#8230;,&#8230;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CLOSE C1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp; 方法2 (高效)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT A.EMP_NAME, A.SALARY, A.GRADE,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B.EMP_NAME, B.SALARY, B.GRADE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP A, EMP B<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE A.EMP_NO = 342<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND B.EMP_NO = 291;</p>
<p>5.使用DECODE函数来减少处理时间<br />
&nbsp; 使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表<br />
&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp; SELECT COUNT(*), SUM(SAL)<br />
&nbsp;&nbsp;&nbsp; FROM EMP<br />
&nbsp;&nbsp;&nbsp; WHERE DEPT_NO = '0020'<br />
&nbsp;&nbsp;&nbsp; AND ENAME LIKE 'SMITH%';</p>
<p>&nbsp;&nbsp;&nbsp; SELECT COUNT(*), SUM(SAL)<br />
&nbsp;&nbsp;&nbsp; FROM EMP<br />
&nbsp;&nbsp;&nbsp; WHERE DEPT_NO = '0030'<br />
&nbsp;&nbsp;&nbsp; AND ENAME LIKE 'SMITH%';</p>
<p>&nbsp;&nbsp;&nbsp; 你可以用DECODE函数高效地得到相同结果<br />
&nbsp;&nbsp;&nbsp; SELECT COUNT(DECODE(DEPT_NO, '0020', 'X', NULL)) D0020_COUNT,<br />
&nbsp;&nbsp;&nbsp; COUNT(DECODE(DEPT_NO, '0030', 'X', NULL)) D0030_COUNT,<br />
&nbsp;&nbsp;&nbsp; SUM(DECODE(DEPT_NO, '0020', SAL, NULL)) D0020_SAL, <br />
&nbsp;&nbsp;&nbsp; SUM(DECODE(DEPT_NO, 0030, SAL, NULL)) D0030_SAL<br />
&nbsp;&nbsp;&nbsp; FROM EMP<br />
&nbsp;&nbsp;&nbsp; WHERE ENAME LIKE 'SMITH%'; </p>
<p>&nbsp; 'X'表示任何一个字段<br />
&nbsp; 类似的，DECODE函数也可以运用于GROUP BY和ORDER BY子句中 </p>
<p>6.用Where子句替换HAVING子句<br />
&nbsp; 避免使用HAVING子句，HAVING只会在检索出所有记录之后才对结果集进行过滤，这个处理需要排序、统计等操作<br />
&nbsp; 如果能通过WHERE子句限制记录的数目，那就能减少这方面的开销<br />
&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp; 低效<br />
&nbsp;&nbsp;&nbsp; SELECT REGION, AVG(LOG_SIZE)<br />
&nbsp;&nbsp;&nbsp; FROM LOCATION<br />
&nbsp;&nbsp;&nbsp; GROUP BY REGION<br />
&nbsp;&nbsp;&nbsp; HAVING REGION REGION != 'SYDNEY'<br />
&nbsp;&nbsp;&nbsp; AND REGION != 'PERTH'</p>
<p>&nbsp;&nbsp;&nbsp; 高效<br />
&nbsp;&nbsp;&nbsp; SELECT REGION, AVG(LOG_SIZE)<br />
&nbsp;&nbsp;&nbsp; FROM LOCATION<br />
&nbsp;&nbsp;&nbsp; WHERE REGION REGION != 'SYDNEY'<br />
&nbsp;&nbsp;&nbsp; AND REGION != 'PERTH'<br />
&nbsp;&nbsp;&nbsp; GROUP BY REGION</p>
<p>7.减少对表的查询<br />
&nbsp; 在含有子查询的SQL语句中，要特别注意减少对表的查询<br />
&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp; 低效<br />
&nbsp;&nbsp;&nbsp; SELECT TAB_NAME<br />
&nbsp;&nbsp;&nbsp; FROM TABLES<br />
&nbsp;&nbsp;&nbsp; WHERE TAB_NAME = (SELECT TAB_NAME <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM TAB_COLUMNS<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE VERSION = 604)<br />
&nbsp;&nbsp;&nbsp; AND DB_VER = (SELECT DB_VER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM TAB_COLUMNS<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE VERSION = 604)</p>
<p>&nbsp;&nbsp;&nbsp; 高效<br />
&nbsp;&nbsp;&nbsp; SELECT TAB_NAME<br />
&nbsp;&nbsp;&nbsp; FROM TABLES<br />
&nbsp;&nbsp;&nbsp; WHERE (TAB_NAME, DB_VER) = (SELECT TAB_NAME, DB_VER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM TAB_COLUMNS<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE VERSION = 604) </p>
<p>&nbsp; Update多个Column例子：<br />
&nbsp;&nbsp;&nbsp; 低效<br />
&nbsp;&nbsp;&nbsp; UPDATE EMP<br />
&nbsp;&nbsp;&nbsp; SET EMP_CAT = (SELECT MAX(CATEGORY) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP_CATEGORIES), <br />
&nbsp;&nbsp;&nbsp; SAL_RANGE = (SELECT MAX(SAL_RANGE) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP_CATEGORIES)<br />
&nbsp;&nbsp;&nbsp; WHERE EMP_DEPT = 0020; </p>
<p>&nbsp;&nbsp;&nbsp; 高效<br />
&nbsp;&nbsp;&nbsp; UPDATE EMP<br />
&nbsp;&nbsp;&nbsp; SET (EMP_CAT, SAL_RANGE) = (SELECT MAX(CATEGORY), MAX(SAL_RANGE)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP_CATEGORIES)<br />
&nbsp;&nbsp;&nbsp; WHERE EMP_DEPT = 0020;</p>
<p>8.使用表的别名(Alias)<br />
&nbsp; 当在SQL语句中连接多个表时，请使用表的别名并把别名前缀于每个Column上<br />
&nbsp; 这样可以减少解析的时间并减少那些由Column歧义引起的语法错误</p>
<p>9.用EXISTS替代IN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp; 在许多基于基础表的查询中，为了满足一个条件，往往需要对另一个表进行联接<br />
&nbsp; 在这种情况下，使用EXISTS(或NOT EXISTS)通常将提高查询的效率<br />
&nbsp;&nbsp;&nbsp; 低效<br />
&nbsp;&nbsp;&nbsp; SELECT *<br />
&nbsp;&nbsp;&nbsp; FROM EMP (基础表)<br />
&nbsp;&nbsp;&nbsp; WHERE EMPNO &gt; 0<br />
&nbsp;&nbsp;&nbsp; AND DEPTNO IN (SELECT DEPTNO<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM DEPT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE LOC = 'MELB')</p>
<p>&nbsp;&nbsp;&nbsp; 高效<br />
&nbsp;&nbsp;&nbsp; SELECT *<br />
&nbsp;&nbsp;&nbsp; FROM EMP (基础表)<br />
&nbsp;&nbsp;&nbsp; WHERE EMPNO &gt; 0<br />
&nbsp;&nbsp;&nbsp; AND EXISTS (SELECT 'X'<br />
&nbsp;&nbsp;&nbsp; FROM DEPT<br />
&nbsp;&nbsp;&nbsp; WHERE DEPT.DEPTNO = EMP.DEPTNO<br />
&nbsp;&nbsp;&nbsp; AND LOC = 'MELB') </p>
<p>10.用NOT EXISTS替代NOT IN<br />
&nbsp; 在子查询中，NOT IN子句将执行一个内部的排序和合并<br />
&nbsp; 无论在哪种情况下，NOT IN都是最低效的，因为它对子查询中的表执行了一个全表遍历<br />
&nbsp; 为了避免使用NOT IN，我们可以把它改写成外连接(Outer Joins)或NOT EXISTS<br />
&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp; SELECT &#8230;<br />
&nbsp;&nbsp;&nbsp; FROM EMP<br />
&nbsp;&nbsp;&nbsp; WHERE DEPT_NO NOT IN (SELECT DEPT_NO<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM DEPT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE DEPT_CAT = 'A');</p>
<p>&nbsp;&nbsp;&nbsp; 为了提高效率改写为<br />
&nbsp;&nbsp;&nbsp; 高效<br />
&nbsp;&nbsp;&nbsp; SELECT &#8230;<br />
&nbsp;&nbsp;&nbsp; FROM EMP A, DEPT B<br />
&nbsp;&nbsp;&nbsp; WHERE A.DEPT_NO = B.DEPT(+)<br />
&nbsp;&nbsp;&nbsp; AND B.DEPT_NO IS NULL<br />
&nbsp;&nbsp;&nbsp; AND B.DEPT_CAT(+) = 'A'</p>
<p>&nbsp;&nbsp;&nbsp; 最高效<br />
&nbsp;&nbsp;&nbsp; SELECT &#8230;<br />
&nbsp;&nbsp;&nbsp; FROM EMP E<br />
&nbsp;&nbsp;&nbsp; WHERE NOT EXISTS (SELECT 'X'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM DEPT D<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE D.DEPT_NO = E.DEPT_NO<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND DEPT_CAT = 'A');</p>
<p>11.用表连接替换EXISTS<br />
&nbsp; 通常来说，采用表连接的方式比EXISTS更有效率<br />
&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp; SELECT ENAME<br />
&nbsp;&nbsp;&nbsp; FROM EMP E<br />
&nbsp;&nbsp;&nbsp; WHERE EXISTS (SELECT 'X'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM DEPT<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE DEPT_NO = E.DEPT_NO<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND DEPT_CAT = 'A');</p>
<p>&nbsp;&nbsp;&nbsp; 更高效<br />
&nbsp;&nbsp;&nbsp; SELECT ENAME<br />
&nbsp;&nbsp;&nbsp; FROM DEPT D, EMP E<br />
&nbsp;&nbsp;&nbsp; WHERE E.DEPT_NO = D.DEPT_NO<br />
&nbsp;&nbsp;&nbsp; AND DEPT_CAT = 'A'; </p>
<p>12.用EXISTS替换DISTINCT <br />
&nbsp; 当提交一个包含多表信息（比如部门表和雇员表）的查询时，避免在SELECT子句中使用DISTINCT，一般可以考虑用EXIST替换<br />
&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp; 低效<br />
&nbsp;&nbsp;&nbsp; SELECT DISTINCT DEPT_NO, DEPT_NAME<br />
&nbsp;&nbsp;&nbsp; FROM DEPT D, EMP E<br />
&nbsp;&nbsp;&nbsp; WHERE D.DEPT_NO = E.DEPT_NO</p>
<p>&nbsp;&nbsp;&nbsp; 高效<br />
&nbsp;&nbsp;&nbsp; SELECT DEPT_NO, DEPT_NAME<br />
&nbsp;&nbsp;&nbsp; FROM DEPT D<br />
&nbsp;&nbsp;&nbsp; WHERE EXISTS (SELECT 'X'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM EMP E<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE E.DEPT_NO = D.DEPT_NO);</p>
<p>&nbsp; EXISTS使查询更为迅速，因为RDBMS核心模块将在子查询的条件一旦满足后，立刻返回结果</p>
<p>13.用索引提高效率<br />
&nbsp; 索引是表的一个概念部分，用来提高检索数据的效率。实际上，ORACLE使用了一个复杂的自平衡B-tree结构<br />
&nbsp; 通常，通过索引查询数据比全表扫描要快。当ORACLE找出执行查询和Update语句的最佳路径时，ORACLE优化器将使用索引<br />
&nbsp; 同样，在联结多个表时使用索引也可以提高效率。另一个使用索引的好处是，它提供了主键（primary key）的唯一性验证</p>
<p>&nbsp; 除了那些LONG或LONG RAW数据类型，你可以索引几乎所有的列<br />
&nbsp; 通常在大型表中使用索引特别有效，当然，在扫描小表时，使用索引同样能提高效率</p>
<p>&nbsp; 虽然使用索引能得到查询效率的提高，但是我们也必须注意到它的代价<br />
&nbsp; 索引需要空间来存储，也需要定期维护，每当有记录在表中增减或索引列被修改时，索引本身也会被修改<br />
&nbsp; 这意味着每条记录的INSERT、DELETE、UPDATE将为此多付出4、5次的磁盘I/O<br />
&nbsp; 因为索引需要额外的存储空间和处理，那些不必要的索引反而会使查询反应时间变慢</p>
<p>&nbsp; ORACLE对索引有两种访问模式：<br />
&nbsp; 1).索引唯一扫描（INDEX UNIQUE SCAN）<br />
&nbsp;&nbsp;&nbsp; 大多数情况下, 优化器通过WHERE子句访问INDEX<br />
&nbsp;&nbsp;&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表LODGING有两个索引：建立在LODGING列上的唯一性索引LODGING_PK和建立在MANAGER列上的非唯一性索引LODGING$MANAGER<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT *<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM LODGING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE LODGING = 'ROSE HILL';</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在内部，上述SQL将被分成两步执行：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先，LODGING_PK索引将通过索引唯一扫描的方式被访问，获得相对应的ROWID；然后通过ROWID访问表的方式执行下一步检索<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果被检索返回的列包括在INDEX列中，ORACLE将不执行第二步的处理（通过ROWID访问表）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 因为检索数据保存在索引中，单单访问索引就可以完全满足查询结果</p>
<p>&nbsp; 2).索引范围查询(INDEX RANGE SCAN)<br />
&nbsp;&nbsp;&nbsp; 适用于两种情况: <br />
&nbsp;&nbsp;&nbsp; 1&gt;.基于唯一性索引的一个范围的检索<br />
&nbsp;&nbsp;&nbsp; 2&gt;.基于非唯一性索引的检索<br />
&nbsp;&nbsp;&nbsp; 例1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT LODGING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM LODGING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE LODGING LIKE 'M%';</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE子句条件包括一系列值，ORACLE将通过索引范围查询的方式查询LODGING_PK<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于索引范围查询将返回一组值，它的效率就要比索引唯一扫描低一些</p>
<p>&nbsp;&nbsp;&nbsp; 例2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT LODGING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM LODGING<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE MANAGER = 'BILL GATES';</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个SQL的执行分两步，LODGING$MANAGER的索引范围查询（得到所有符合条件记录的ROWID），通过ROWID访问表得到LODGING列的值<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于LODGING$MANAGER是一个非唯一性的索引，数据库不能对它执行索引唯一扫描</p>
<p>&nbsp; WHERE子句中，如果索引列所对应的值的第一个字符由通配符（WILDCARD）开始，索引将不被采用<br />
&nbsp;&nbsp;&nbsp; SELECT LODGING<br />
&nbsp;&nbsp;&nbsp; FROM LODGING<br />
&nbsp;&nbsp;&nbsp; WHERE MANAGER LIKE '％HANMAN';</p>
<p>&nbsp; 在这种情况下，ORACLE将使用全表扫描</p>
<p>14.避免在索引列上使用计算<br />
&nbsp; WHERE子句中，如果索引列是函数的一部分，优化器将不使用索引而使用全表扫描<br />
&nbsp; 例如：<br />
&nbsp;&nbsp;&nbsp; 低效<br />
&nbsp;&nbsp;&nbsp; SELECT &#8230;<br />
&nbsp;&nbsp;&nbsp; FROM DEPT<br />
&nbsp;&nbsp;&nbsp; WHERE SAL * 12 &gt; 25000;</p>
<p>&nbsp;&nbsp;&nbsp; 高效<br />
&nbsp;&nbsp;&nbsp; SELECT &#8230;<br />
&nbsp;&nbsp;&nbsp; FROM DEPT<br />
&nbsp;&nbsp;&nbsp; WHERE SAL &gt; 25000/12;</p>
<p>&nbsp; 请务必注意，检索中不要对索引列进行处理，如：TRIM，TO_DATE，类型转换等操作，破坏索引，使用全表扫描，影响SQL执行效率</p>
<p>15.避免在索引列上使用IS NULL和IS NOT NULL<br />
&nbsp; 避免在索引中使用任何可以为空的列，ORACLE将无法使用该索引<br />
&nbsp; 对于单列索引，如果列包含空值，索引中将不存在此记录；<br />
&nbsp; 对于复合索引，如果每个列都为空，索引中同样不存在此记录。如果至少有一个列不为空，则记录存在于索引中</p>
<p>&nbsp; 如果唯一性索引建立在表的A列和B列上，并且表中存在一条记录的A,B值为(123,null)，<br />
&nbsp; ORACLE将不接受下一条具有相同A,B值（123,null）的记录插入<br />
&nbsp; 如果所有的索引列都为空，ORACLE将认为整个键值为空，而空不可能等于空，因此你可以插入1000条具有相同键值的记录，当然它们都是空！<br />
&nbsp; 因为空值不存在于索引列中，所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引</p>
<p>&nbsp; 低效（索引失效）<br />
&nbsp; SELECT &#8230;<br />
&nbsp; FROM DEPARTMENT<br />
&nbsp; WHERE DEPT_CODE IS NOT NULL</p>
<p>16.使用UNION-ALL和UNION<br />
&nbsp; 当SQL语句需要UNION两个查询结果集合时，这两个结果集合会以UNION-ALL的方式被合并，然后在输出最终结果前进行排序<br />
&nbsp; 如果用UNION ALL替代UNION，这样排序就不是必要了，效率就会因此得到提高</p>
<p>&nbsp; 需要注意的是，UNION ALL将重复输出两个结果集合中相同记录，因此还是要从业务需求分析使用UNION ALL的可行性</p>
<p><br />
关于索引下列经验请参考: <br />
1).如果检索数据量超过30%的表中记录数，使用索引将没有显著的效率提高<br />
2).在特定情况下，使用索引也许会比全表扫描慢，但这是同一个数量级上的差距；而通常情况下，使用索引比全表扫描要快几倍乃至几千倍！</p>
<p>其他具体内容请参考《ORACLE SQL性能优化系列》</p>
<p>17.使用PrepareStatement<br />
在同一个方法中，当循环使用SQL文时，为了提高性能，<br />
请使用PreparedStatement。注意，<br />
仅限使用于少数的模块。<br />
方法如下：</p>
<p>? PreparedStatement stmt<br />
　　　= conn.prepareStatement("select a from TABLE_A where b=? c=?");</p>
<p>　for(?? ){<br />
???? stmt.setInt(1, varB);　　　　　<br />
???? stmt.setString(2, varC);　　　 　<br />
? 　 ResultSet rst = stmt.executeQuery();</p>
<p>　}<br />
</p>
<img src ="http://www.blogjava.net/SkyWinder/aggbug/149863.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/SkyWinder/" target="_blank">枫中玎玲</a> 2007-09-30 13:07 <a href="http://www.blogjava.net/SkyWinder/archive/2007/09/30/149863.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】java里抽象类和接口的区别</title><link>http://www.blogjava.net/SkyWinder/archive/2007/03/21/105351.html</link><dc:creator>枫中玎玲</dc:creator><author>枫中玎玲</author><pubDate>Wed, 21 Mar 2007 11:29:00 GMT</pubDate><guid>http://www.blogjava.net/SkyWinder/archive/2007/03/21/105351.html</guid><wfw:comment>http://www.blogjava.net/SkyWinder/comments/105351.html</wfw:comment><comments>http://www.blogjava.net/SkyWinder/archive/2007/03/21/105351.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/SkyWinder/comments/commentRss/105351.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/SkyWinder/services/trackbacks/105351.html</trackback:ping><description><![CDATA[下面的这篇文章讲的十分透彻了，所以转载之<br /><font face="Verdana, Arial, Helvetica, sans-serif">abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制，正是由于这两种机制的存在，才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性，甚至可以相互替换，因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实，两者之间还是有很大的区别的，对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析，试图给开发者提供一个在二者之间进行选择的依据。  <br /><br />理解抽象类  <br /><br />abstract class和interface在Java语言中都是用来进行抽象类（本文中的抽象类并非从abstract class翻译而来，它表示的是一个抽象体，而abstract class为Java语言中用于定义抽象类的一种方法，请读者注意区分）定义的，那么什么是抽象类，使用抽象类能为我们带来什么好处呢？  <br /><br />在面向对象的概念中，我们知道所有的对象都是通过类来描绘的，但是反过来却不是这样。并不是所有的类都是用来描绘对象的，如果一个类中没有包含足够的信息来描绘一个具体的对象，这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念，是对一系列看上去不同，但是本质上相同的具体概念的抽象。比如：如果我们进行一个图形编辑软件的开发，就会发现问题领域存在着圆、三角形这样一些具体概念，它们是不同的，但是它们又都属于形状这样一个概念，形状这个概念在问题领域是不存在的，它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念，所以用以表征抽象概念的抽象类是不能够实例化的。  <br /><br />在面向对象领域，抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述，但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类，而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体，因此它可以是不允许修改的；同时，通过从这个抽象体派生，也可扩展此模块的行为功能。熟悉OCP的读者一定知道，为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)，抽象类是其中的关键所在。  <br /><br /><br />从语法定义层面看abstract class和interface  <br /><br />在语法层面，Java语言对于abstract class和interface给出了不同的定义方式，下面以定义一个名为Demo的抽象类为例来说明这种不同。  <br /><br />使用abstract class的方式定义Demo抽象类的方式如下：  <br /><br />abstract class Demo ｛  <br /> abstract void method1();  <br /> abstract void method2();  <br /> …  <br />｝  <br /><br />使用interface的方式定义Demo抽象类的方式如下：  <br /><br />interface Demo {  <br /> void method1();  <br /> void method2();  <br /> …  <br />}  <br /><br />在abstract class方式中，Demo可以有自己的数据成员，也可以有非abstarct的成员方法，而在interface方式的实现中，Demo只能够有静态的不能被修改的数据成员（也就是必须是static final的，不过在interface中一般不定义数据成员），所有的成员方法都是abstract的。从某种意义上说，interface是一种特殊形式的abstract class。  <br /><br />      从编程的角度来看，abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。  <br /><br />首先，abstract class在Java语言中表示的是一种继承关系，一个类只能使用一次继承关系。但是，一个类却可以实现多个interface。也许，这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。  <br /><br />其次，在abstract class的定义中，我们可以赋予方法的默认行为。但是在interface的定义中，方法却不能拥有默认行为，为了绕过这个限制，必须使用委托，但是这会 增加一些复杂性，有时会造成很大的麻烦。  <br /><br />在接口中不能定义默认行为还存在另一个比较严重的问题，那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面（一般通过abstract class或者interface来表示）以适应新的情况（比如，添加新的方法或者给已用的方法中添加新的参数）时，就会非常的麻烦，可能要花费很多的时间（对于派生类很多的情况，尤为如此）。但是如果界面是通过abstract class来实现的，那么可能就只需要修改定义在abstract class中的默认行为就可以了。  <br /><br />同样，如果不能在抽象类中定义默认行为，就会导致同样的方法实现出现在该抽象类的每一个派生类中，违反了"one rule，one place"原则，造成代码重复，同样不利于以后的维护。因此，在abstract class和interface间进行选择时要非常的小心。  <br /><br /><br />从设计理念层面看abstract class和interface  <br /><br />上面主要从语法定义和编程的角度论述了abstract class和interface的区别，这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面：abstract class和interface所反映出的设计理念，来分析一下二者的区别。作者认为，从这个层面进行分析才能理解二者概念的本质所在。  <br /><br />前面已经提到过，abstarct class在Java语言中体现了一种继承关系，要想使得继承关系合理，父类和派生类之间必须存在"is a"关系，即父类和派生类在概念本质上应该是相同的（参考文献〔3〕中有关于"is a"关系的大篇幅深入的论述，有兴趣的读者可以参考）。对于interface 来说则不然，并不要求interface的实现者和interface定义在概念本质上是一致的，仅仅是实现了interface定义的契约而已。为了使论述便于理解，下面将通过一个简单的实例进行说明。  <br /><br />考虑这样一个例子，假设在我们的问题领域中有一个关于Door的抽象概念，该Door具有执行两个动作open和close，此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型，定义方式分别如下所示：  <br /><br />使用abstract class方式定义Door：  <br /><br />abstract class Door {  <br /> abstract void open();  <br /> abstract void close()；  <br />}  <br /><br />   <br />使用interface方式定义Door：  <br /><br /><br />interface Door {  <br /> void open();  <br /> void close();  <br />}  <br /><br />   <br />其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。  <br /><br />如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢（在本例中，主要是为了展示abstract class和interface反映在设计理念上的区别，其他方面无关的问题都做了简化或者忽略）？下面将罗列出可能的解决方案，并从设计理念层面对这些不同的方案进行分析。  <br /><br />解决方案一：  <br /><br />简单的在Door的定义中增加一个alarm方法，如下：  <br /><br />abstract class Door {  <br /> abstract void open();  <br /> abstract void close()；  <br /> abstract void alarm();  <br />}  <br /><br />   <br />或者  <br /><br />interface Door {  <br /> void open();  <br /> void close();  <br /> void alarm();  <br />}  <br /><br />   <br />那么具有报警功能的AlarmDoor的定义方式如下：  <br /><br />class AlarmDoor extends Door {  <br /> void open() { … }  <br /> void close() { … }  <br /> void alarm() { … }  <br />}  <br /><br />   <br />或者  <br /><br />class AlarmDoor implements Door ｛  <br /> void open() { … }  <br /> void close() { … }  <br /> void alarm() { … }  <br />｝  <br /><br />这种方法违反了面向对象设计中的一个核心原则ISP（Interface Segregation Priciple），在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变（比如：修改alarm方法的参数）而改变，反之依然。  <br /><br />解决方案二：  <br /><br />既然open、close和alarm属于两个不同的概念，根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有：这两个概念都使用abstract class方式定义；两个概念都使用interface方式定义；一个概念使用abstract class方式定义，另一个概念使用interface方式定义。  <br /><br />显然，由于Java语言不支持多重继承，所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的，但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。  <br /><br />如果两个概念都使用interface方式来定义，那么就反映出两个问题：1、我们可能没有理解清楚问题领域，AlarmDoor在概念本质上到底是Door还是报警器？2、如果我们对于问题领域的理解没有问题，比如：我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的，那么我们在实现时就没有能够正确的揭示我们的设计意图，因为在这两个概念的定义上（均使用interface方式定义）反映不出上述含义。  <br /><br />如果我们对于问题领域的理解是：AlarmDoor在概念本质上是Door，同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢？前面已经说过，abstract class在Java语言中表示一种继承关系，而继承关系在本质上是"is a"关系。所以对于Door这个概念，我们应该使用abstarct class方式来定义。另外，AlarmDoor又具有报警功能，说明它又能够完成报警概念中定义的行为，所以报警概念可以通过interface方式定义。如下所示：  <br /><br />abstract class Door {  <br /> abstract void open();  <br /> abstract void close()；  <br />}  <br />interface Alarm {  <br /> void alarm();  <br />}  <br />class AlarmDoor extends Door implements Alarm {  <br /> void open() { … }  <br /> void close() { … }  <br />    void alarm() { … }  <br />}  <br /><br />   <br />这种实现方式基本上能够明确的反映出我们对于问题领域的理解，正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系，interface表示的是"like a"关系，大家在选择时可以作为一个依据，当然这是建立在对问题领域的理解上的，比如：如果我们认为AlarmDoor在概念本质上是报警器，同时又具有Door的功能，那么上述的定义方式就要反过来了。</font><img src ="http://www.blogjava.net/SkyWinder/aggbug/105351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/SkyWinder/" target="_blank">枫中玎玲</a> 2007-03-21 19:29 <a href="http://www.blogjava.net/SkyWinder/archive/2007/03/21/105351.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】SOA是什么？</title><link>http://www.blogjava.net/SkyWinder/archive/2006/11/18/81874.html</link><dc:creator>枫中玎玲</dc:creator><author>枫中玎玲</author><pubDate>Fri, 17 Nov 2006 16:01:00 GMT</pubDate><guid>http://www.blogjava.net/SkyWinder/archive/2006/11/18/81874.html</guid><wfw:comment>http://www.blogjava.net/SkyWinder/comments/81874.html</wfw:comment><comments>http://www.blogjava.net/SkyWinder/archive/2006/11/18/81874.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/SkyWinder/comments/commentRss/81874.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/SkyWinder/services/trackbacks/81874.html</trackback:ping><description><![CDATA[面向服务的体系结构（service-oriented architecture，SOA）是一个组件模型，它将应用程序的不同功能单元（称为服务）通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的，它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种这样的系统中的服务可以以一种统一和通用的方式进行交互。 <br /><br />这种具有中立的接口定义（没有强制绑定到特定的实现上）的特征称为服务之间的松耦合。松耦合系统的好处有两点，一点是它的灵活性，另一点是，当组成整个应用程序的每个服务的内部结构和实现逐渐地发生改变时，它能够继续存在。而另一方面，紧耦合意味着应用程序的不同组件之间的接口与其功能和结构是紧密相连的，因而当需要对部分或整个应用程序进行某种形式的更改时，它们就显得非常脆弱。 <br /><br />对松耦合的系统的需要来源于业务应用程序需要根据业务的需要变得更加灵活，以适应不断变化的环境，比如经常改变的政策、业务级别、业务重点、合作伙伴关系、行业地位以及其他与业务有关的因素，这些因素甚至会影响业务的性质。我们称能够灵活地适应环境变化的业务为按需（On demand）业务，在按需业务中，一旦需要，就可以对完成或执行任务的方式进行必要的更改。 <br /><br />虽然面向服务的体系结构不是一个新鲜事物，但它却是更传统的面向对象的模型的替代模型，面向对象的模型是紧耦合的，已经存在二十多年了。虽然基于 SOA 的系统并不排除使用面向对象的设计来构建单个服务，但是其整体设计却是面向服务的。由于它考虑到了系统内的对象，所以虽然 SOA 是基于对象的，但是作为一个整体，它却不是面向对象的。不同之处在于接口本身。SOA 系统原型的一个典型例子是通用对象请求代理体系结构（Common Object Request Broker Architecture，CORBA），它已经出现很长时间了，其定义的概念与 SOA 相似。 <br /><br />然而，现在的 SOA 已经有所不同了，因为它依赖于一些更新的进展，这些进展是以可扩展标记语言（eXtensible Markup Language，XML）为基础的。通过使用基于 XML 的语言（称为 Web 服务描述语言（Web Services Definition Language，WSDL））来描述接口，服务已经转到更动态且更灵活的接口系统中，非以前 CORBA 中的接口描述语言（Interface Definition Language，IDL）可比了。 <br /><br />Web 服务并不是实现 SOA 的惟一方式。前面刚讲的 CORBA 是另一种方式，这样就有了面向消息的中间件（Message-Oriented Middleware）系统，比如 IBM 的 MQseries。但是为了建立体系结构模型，您所需要的并不只是服务描述。您需要定义整个应用程序如何在服务之间执行其工作流。您尤其需要找到业务的操作和业务中所使用的软件的操作之间的转换点。因此，SOA 应该能够将业务的商业流程与它们的技术流程联系起来，并且映射这两者之间的关系。例如，给供应商付款的操作是商业流程，而更新您的零件数据库，以包括进新供应的货物却是技术流程。因而，工作流还可以在 SOA 的设计中扮演重要的角色。 <br /><br />此外，动态业务的工作流不仅可以包括部门之间的操作，甚至还可以包括与不为您控制的外部合作伙伴进行的操作。因此，为了提高效率，您需要定义应该如何得知服务之间的关系的策略，这种策略常常采用服务级协定和操作策略的形式。 <br /><br />最后，所有这些都必须处于一个信任和可靠的环境之中，以同预期的一样根据约定的条款来执行流程。因此，安全、信任和可靠的消息传递应该在任何 SOA 中都起着重要的作用。 <br /><br />我可以用面向服务的体系结构做什么？ <br />对 SOA 的需要来源于需要使业务 IT 系统变得更加灵活，以适应业务中的改变。通过允许强定义的关系和依然灵活的特定实现，IT 系统既可以利用现有系统的功能，又可以准备在以后做一些改变来满足它们之间交互的需要。 <br /><br />下面举一个具体的例子。一个服装零售组织拥有 500 家国际连锁店，它们常常需要更改设计来赶上时尚的潮流。这可能意味着不仅需要更改样式和颜色，甚至还可能需要更换布料、制造商和可交付的产品。如果零售商和制造商之间的系统不兼容，那么从一个供应商到另一个供应商的更换可能就是一个非常复杂的软件流程。通过利用 WSDL 接口在操作方面的灵活性，每个公司都可以将它们的现有系统保持现状，而仅仅匹配 WSDL 接口并制订新的服务级协定，这样就不必完全重构它们的软件系统了。这是业务的水平改变，也就是说，它们改变的是合作伙伴，而所有的业务操作基本上都保持不变。这里，业务接口可以作少许改变，而内部操作却不需要改变，之所以这样做，仅仅是为了能够与外部合作伙伴一起工作。 <br /><br />另一种形式是内部改变，在这种改变中，零售组织现在决定它还将把连锁零售商店内的一些地方出租给专卖流行衣服的小商店，这可以看作是采用店中店（store-in-store）的业务模型。这里，虽然公司的大多数业务操作都保持不变，但是它们现在需要新的内部软件来处理这样的出租安排。尽管在内部软件系统可以承受全面的检修，但是它们需要在这样做的同时不会对与现有的供应商系统的交互产生大的影响。在这种情况下，SOA 模型保持原封不动，而内部实现却发生了变化。虽然可以将新的方面添加到 SOA 模型中来加入新的出租安排的职责，但是正常的零售管理系统继续如往常一样。 <br /><br />为了延续内部改变的观念，IT 经理可能会发现，软件的新配置还可以以另外的一种方式加以使用，比如出租粘贴海报的地方以供广告之用。这里，新的业务提议是通过在新的设计中重用灵活的 SOA 模型得出的。这是来自 SOA 模型的新成果，并且还是一个新的机会，而这样的新机会在以前可能是不会有的。 <br /><br />垂直改变也是可能的，在这种改变中，零售商从销售他们自己的服装完全转变到专门通过店中店模型出租地方。如果垂直改变完全从最底层开始的话，就会带来 SOA 模型结构的显著改变，与之一起改变的还可能有新的系统、软件、流程以及关系。在这种情况下，SOA 模型的好处是它从业务操作和流程的角度考虑问题而不是从应用程序和程序的角度考虑问题，这使得业务管理可以根据业务的操作清楚地确定什么需要添加、修改或删除。然后可以将软件系统构造为适合业务处理的方式，而不是在许多现有的软件平台上常常看到的其他方式。 <br /><br />正如您可以看到的，在这里，改变和 SOA 系统适应改变的能力是最重要的部分。对于开发人员来说，这样的改变无论是在他们工作的范围之内还是在他们工作的范围之外都有可能发生，这取决于是否有改变需要知道接口是如何定义的以及它们相互之间如何进行交互。与开发人员不同的是，架构师的作用就是引起对 SOA 模型大的改变。这种分工，就是让开发人员集中精力于创建作为服务定义的功能单元，而让架构师和建模人员集中精力于如何将这些单元适当地组织在一起，它已经有十多年的历史了，通常用统一建模语言（Universal Modeling Language，UML），并且描述成模型驱动的体系结构（Model-Driven Architecture，MDA）。<img src ="http://www.blogjava.net/SkyWinder/aggbug/81874.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/SkyWinder/" target="_blank">枫中玎玲</a> 2006-11-18 00:01 <a href="http://www.blogjava.net/SkyWinder/archive/2006/11/18/81874.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>『转贴』如何选择Web开发框架</title><link>http://www.blogjava.net/SkyWinder/archive/2006/08/06/62076.html</link><dc:creator>枫中玎玲</dc:creator><author>枫中玎玲</author><pubDate>Sun, 06 Aug 2006 12:32:00 GMT</pubDate><guid>http://www.blogjava.net/SkyWinder/archive/2006/08/06/62076.html</guid><wfw:comment>http://www.blogjava.net/SkyWinder/comments/62076.html</wfw:comment><comments>http://www.blogjava.net/SkyWinder/archive/2006/08/06/62076.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/SkyWinder/comments/commentRss/62076.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/SkyWinder/services/trackbacks/62076.html</trackback:ping><description><![CDATA[
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">如何选择</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架的选择，始终是个仁者见仁、智者见智的事情。尤其是</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层的开发框架，数量非常多，而且各有特色，如：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Struts</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">、</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">WebWork</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">、</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Spring MVC</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">、</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Tapestry</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">、</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">JSF</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">、</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">WebPage3.0……</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">等等。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">下面先来看看为什么要使用</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">一：使用框架的必然性</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">框架，即</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">framework</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">。其实就是某种应用的半成品，把不同应用程序中有共性的一些东西抽取出来，做成一个半成品程序，这样的半成品就是所谓的程序框架。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">软件系统发展到今天已经很复杂了，特别是服务器端软件，涉及到的知识，内容，问题太多。在某些方面使用别人成熟的框架，就相当于让别人帮你完成一些基础工作，你只需要集中精力完成系统的业务逻辑设计。这样每次开发就不用白手起家，而是可以在这个基础上开始搭建。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">使用框架的最大好处：减少重复开发工作量、缩短开发时间、降低开发成本。同时还有其它的好处，如：使程序设计更合理、程序运行更稳定等。基于这些原因，基本上现在在开发中，都会选用某些合适的开发框架，来帮助快速高效的开发应用系统。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">了解了使用框架的必然性，下面来看看如何选择，当然我们的话题集中在</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层的开发框架。在谈这个问题之前，先来看看我们在</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发中究竟需要做些什么工作：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">二：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层开发的工作</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">在</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">J2EE</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发中，分层是基本的思想，</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">3</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层架构或者多层架构早已深入人心，在这里我们就把目光集中到</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层，看看到底</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层开发做了那些工作：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />1</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：数据展示</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层需要从逻辑层获取需要展示的数据，然后以合理的方式在页面进行展示</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />2</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：人机交互</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">用户需要从界面上输入数据，在界面上进行按钮点击，进而触发事件，标准的事件驱动模型，然后跟后台进行数据交换，出现新的界面。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />3</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：收集数据，调用逻辑层接口</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层收到用户的事件请求，需要调用相应的逻辑层接口来进行处理，</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层是不会有任何逻辑处理的。调用逻辑层接口，需要传递参数，这时需要收集用户在界面上输入的数据，然后进行组织，组织成为逻辑层接口需要的数据封装形式（通常都是</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">ValueObject</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">）。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />4</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：根据逻辑层的数据来重新展示页面</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">逻辑层处理完了，需要返回数据或信息到界面上。这个时候</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层需要根据返回的值选择合适的页面，然后展示这些数据或者信息。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">从上面可以看出，</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层开发的主要工作集中在展示上，也就是图形用户界面。这一部分是用户直观感受应用程序的窗口，也是用户要求最多的地方，其表现形式也是最丰富的。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">三：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层开发的步骤</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">下面再来总结一下</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层开发的大致步骤（也就是需要开发人员做的工作）：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">注意：这里讨论的</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层开发，是不使用任何开发框架时候的开发。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
								<br />1</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：写页面</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Html</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">，到底有哪些数据需要在界面上表现</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />2</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：每个数据的具体表现形式，如：有的需要表现成为下拉列表，有的需要表现成为单选按钮等。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />3</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：界面表现形式的逻辑布局，所谓逻辑布局是指某些数据的表现形式应该放在前面，某些应该放在后面；某些放在上面，某些放在下面。如：某个请假申请的业务，有请假开始时间和结束时间，很明显开始时间的表现就应该排在结束时间的前面。而美工是负责最后页面的美观，一般美工不能动界面的逻辑布局。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />4</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：完成前面</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">3</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">步，页面的表现形式的大致模样就有了，下面需要来做功能性的开发。第一个就是这些表现形式的值的来源，如：下拉列表显示的值从什么地方来。值的来源方式很多，有数据库中来、固定值、某断程序运行的中间结果、前面页面传递过来等等，当然典型的还是来自数据库。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">好了，确定了值的来源，开发人员就要写代码来获取这些值，然后把这些值赋值到对应的表现形式里面。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />5</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：还有一些比较特殊，也就是真实操作的是一类值，但是在界面上显示的是另一类值，比如：数据库中有用户编号，到了界面上就得显示用户姓名，但是所有的操作都是要操作用户编号的。我们把这种情况分做：真实值和表现值，他们有一定的内在联系。这些都是要开发人员去转化和维护的。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />6</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：接下来就应该开发功能性的事件响应了。用户点击了某个按钮或者触发了某个事件，首先是客户端：数据检测、客户端事件处理；然后提交到服务端，服务端要获取到客户端提交的数据，然后调用相应的逻辑层接口来响应。当然如何写逻辑层的实现这里就不去谈论了。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />7</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：逻辑层执行完过后，返回数据和信息到</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层，开发人员还需要写代码去处理，选择哪个页面来显示，如何显示这些数据和信息等。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />8</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：在整个交互的过程中，还必须考虑到如何控制权限，如：某些数据不能显示，某些数据不能编辑等等；同样还需要考虑到消息的配置和国际化等等。这些功能起源于逻辑层，但是实际的控制要到</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">层，这些都需要开发人员来控制。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />9</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：完成了上面的开发步骤，页面基本的功能开发就告一段落，接下来开发人员需要考虑页面美观的问题了。大家可能会说：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">“</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">不是有美工吗，还需要开发人员干什么？</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">”</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">。事实上美工多半只能出一个静态页面的美化模版，美工对于一推</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Java</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">代码和</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Html</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">的混杂物，多半是没有办法的，更不要说还有一些内容是动态生成的，美工就更不可能搞定了。还是得开发人员上阵，按照美工给的模版，开始添加</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Css</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">class</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">、</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">id</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">、</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">style…… <br />10</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：完成上面的开发，基本页面的开发工作就完成了，最后的一个步骤就是把各个页面有机的组织起来，开发应用程序的整体应用导航框架，通常就是菜单，然后把各个功能页面跟菜单结合起来，形成一个完整的应用。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">在这里我们省略了开发期反复的调试过程，仅总结开发的步骤。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">四：选择</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架的目的</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">了解了如果没有框架，我们需要做的工作，这对选择框架有非常大的帮助。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">框架，直白点说，就是一个半成品，能够帮我们做一些事情的半成品。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">框架的选择，就是看哪个框架最合适，从而减少开发的工作量，提高开发的效率和质量，并有效减少维护的工作量，最终达到节约综合开发成本，获取更多的收益。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">五：选择</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架的标准</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">声明：这里所谈的选择</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架的标准，只是我们的总结和一家之言，并不是放之四海而皆准的真理，请根据您的体会客观的看待我们的总结。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />
						</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">另外：我们这里更多的讨论业务功能性应用程序的</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />1</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：选择能够对我们的开发过程提供更多、更好帮助的</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />2</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架的学习一定要简单，上手一定要快，没有什么比使用能得到更深的体会。那些动不动就需要半个月或者一个月学习周期的框架，实在是有些恐怖。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />3</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：一定要能得到很好的技术支持，在应用的过程中，或多或少都会出现这样或者那样的问题，如果不能很快很好的解决，会对整个项目开发带来影响。一定要考虑综合成本，其实这是目前应用开源软件最大的问题，碰到问题除了死肯文档就是查阅源代码，或者是网上搜寻解决的办法，通常一个问题就会导致</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">1-2</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">天的开发停顿，严重的甚至需要一个星期或者更长，一个项目有上这么几次，项目整体的开发成本嗖嗖的就上去了。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />4</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架结合其他技术的能力一定要强，比如：在逻辑层要使用</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Spring</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">或者</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Ejb3</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">，那么</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架一定要能很容易，很方便的与它们进行结合。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />5</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架的扩展能力一定要强。在好的框架都有力所不及的地方，这就要求能很容易的扩展</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架的功能，以满足新的业务需要。同时要注意扩展的简单性，如果扩展框架的功能代价非常大，还不如不用呢。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />6</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架最好能提供可视化的开发和配置，可视化开发对开发效率的提高，已经得到业界公认。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />7</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架的设计结构一定要合理，应用程序会基于这个框架，框架设计的不合理会大大影响到整个应用的可扩展性。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />8</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架一定要是运行稳定的，运行效率高的。框架的稳定性和运行效率直接影响到整个系统的稳定性和效率。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />9</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架一定要能很好的结合目前公司的积累。在多年的开发中已有了很多积累，不能因为使用</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架就不能再使用了，那未免有些得不偿失。</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
								<br />10</span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：选择开发框架另外要注意的一点就是：任何开发框架都不可能是十全十美的，也不可能是适应所有的应用场景的，也就是说任何开发框架都有它适用的范围。所以选择的时候要注意判断应用的场景和开发框架的适用性。</span>
				</p>
				<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				</p>
		</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">发框架的功能，以满足新的业务需要。同时要注意扩展的简单性，如果扩展框架的功能代价非常大，还不如不用呢。</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
				<br />6</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架最好能提供可视化的开发和配置，可视化开发对开发效率的提高，已经得到业界公认。</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
				<br />7</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架的设计结构一定要合理，应用程序会基于这个框架，框架设计的不合理会大大影响到整个应用的可扩展性。</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
				<br />8</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架一定要是运行稳定的，运行效率高的。框架的稳定性和运行效率直接影响到整个系统的稳定性和效率。</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
				<br />9</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架一定要能很好的结合目前公司的积累。在多年的开发中已有了很多积累，不能因为使用</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Web</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">开发框架就不能再使用了，那未免有些得不偿失。</span>
		<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">
				<br />10</span>
		<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">：选择开发框架另外要注意的一点就是：任何开发框架都不可能是十全十美的，也不可能是适应所有的应用场景的，也就是说任何开发框架都有它适用的范围。所以选择的时候要注意判断应用的场景和开发框架的适用性。</span>
<img src ="http://www.blogjava.net/SkyWinder/aggbug/62076.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/SkyWinder/" target="_blank">枫中玎玲</a> 2006-08-06 20:32 <a href="http://www.blogjava.net/SkyWinder/archive/2006/08/06/62076.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转贴：struts应用</title><link>http://www.blogjava.net/SkyWinder/archive/2006/07/30/60815.html</link><dc:creator>枫中玎玲</dc:creator><author>枫中玎玲</author><pubDate>Sun, 30 Jul 2006 01:13:00 GMT</pubDate><guid>http://www.blogjava.net/SkyWinder/archive/2006/07/30/60815.html</guid><wfw:comment>http://www.blogjava.net/SkyWinder/comments/60815.html</wfw:comment><comments>http://www.blogjava.net/SkyWinder/archive/2006/07/30/60815.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/SkyWinder/comments/commentRss/60815.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/SkyWinder/services/trackbacks/60815.html</trackback:ping><description><![CDATA[
		<table class="MsoNormalTable" style="WIDTH: 100%; mso-cellspacing: 0cm; mso-padding-alt: 0cm 0cm 0cm 0cm" cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes">
								<td style="BORDER-RIGHT: #ece9d8; PADDING-RIGHT: 0cm; BORDER-TOP: #ece9d8; PADDING-LEFT: 0cm; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: #ece9d8; BACKGROUND-COLOR: transparent">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
												<b>
														<span lang="EN-US" style="COLOR: black; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">Struts</span>
												</b>
												<b>
														<span style="COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma">应用</span>
												</b>
												<b>
														<span style="COLOR: black; FONT-FAMILY: Tahoma; mso-font-kerning: 0pt">
														</span>
												</b>
												<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">
														<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?>
														<o:p>
														</o:p>
												</span>
										</p>
								</td>
						</tr>
						<tr style="HEIGHT: 6pt; mso-yfti-irow: 1">
								<td style="BORDER-RIGHT: #ece9d8; PADDING-RIGHT: 0cm; BORDER-TOP: #ece9d8; PADDING-LEFT: 0cm; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: #ece9d8; HEIGHT: 6pt; BACKGROUND-COLOR: transparent">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
												<span lang="EN-US" style="FONT-SIZE: 6pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体; mso-bidi-font-size: 9.0pt">
														<o:p> </o:p>
												</span>
										</p>
								</td>
						</tr>
						<tr style="mso-yfti-irow: 2; mso-yfti-lastrow: yes">
								<td style="BORDER-RIGHT: #ece9d8; PADDING-RIGHT: 0cm; BORDER-TOP: #ece9d8; PADDING-LEFT: 0cm; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: #ece9d8; BACKGROUND-COLOR: transparent">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
												<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"> <o:p></o:p></span>
										</p>
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align="left">
												<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">编者按：当作者<span lang="EN-US"> Chuck Cavaness</span>（著有《<span lang="EN-US">Programming Jakarta Struts</span>》一书）所在的网络公司决定采用<span lang="EN-US">Struts</span>框架之后，<span lang="EN-US">Chuck</span>曾经花费了好几个月来研究如何用它来构建公司的应用系统。本文叙述的正是作者在运用<span lang="EN-US">Struts</span>过程中来之不易的若干经验和心得。如果你是个负责通过<span lang="EN-US">jsp</span>和<span lang="EN-US">servlet</span>开发<span lang="EN-US">Web</span>应用的<span lang="EN-US">Java</span>程序员，并且也正在考虑采用基于<span lang="EN-US">Struts</span>的构建方法的话，那么你会在这里发现很多颇有见地同时也很有价值的信息。<span lang="EN-US"><br /><br />1. </span>只在必要的时候才考虑扩展<span lang="EN-US">Struts</span>框架<span lang="EN-US"><br /><br /></span>一个好的<span lang="EN-US">framework</span>有很多优点，首先，它必须能够满足用户的可预见的需求。为此<span lang="EN-US"> Struts</span>为<span lang="EN-US">Web </span>应用提供了一个通用的架构，这样开发人员可以把精力集中在如何解决实际业务问题上。其次，一个好的<span lang="EN-US">framework</span>还必须能够在适当的地方提供扩展接口，以便应用程序能扩展该框架来更好的适应使用者的实际需要。<span lang="EN-US"><br /><br /></span>如果<span lang="EN-US">Struts framework</span>在任何场合，任何项目中都能很好的满足需求，那真是太棒了。但是实际上，没有一个框架声称能做到这一点。一定会有一些特定的应用需求是框架的开发者们无法预见到的。因此，最好的办法就是提供足够的扩展接口，使得开发工程师能够调整<span lang="EN-US">struts</span>来更好的符合他们的特殊要求。<span lang="EN-US"><br /><br /></span>在<span lang="EN-US">Struts framework</span>中有很多地方可供扩展和定制。几乎所有的配置类都能被替换为某个用户定制的版本，这只要简单的修改一下<span lang="EN-US">Struts</span>的配置文件就可以做到。<span lang="EN-US"><br /><br /></span>其他组件如<span lang="EN-US">ActionServlet</span>和<span lang="EN-US"> RequestProcessor </span>也能用自定义的版本代替<span lang="EN-US">. </span>甚至连<span lang="EN-US">Struts 1.1</span>里才有的新特性也是按照扩展的原则来设计的。例如，在异常处理机制中就允许用户定制异常处理的句柄，以便更好的对应用系统发生的错误做出响应。<span lang="EN-US"><br /><br /></span>作为框架的这种可调整特性在它更适合你的应用的同时也在很大的程度上影响了项目开发的效果。首先，由于您的应用是基于一个现有的成熟的、稳定的<span lang="EN-US">framework</span>如<span lang="EN-US">Struts</span>，测试过程中发现的错误数量将会大大减少，同时也能缩短开发时间和减少资源的投入。因为你不再需要投入开发力量用于编写基础框架的代码了。<span lang="EN-US"><br /><br /></span>然而<span lang="EN-US">, </span>实现更多的功能是要花费更大的代价的。我们必须小心避免不必要的滥用扩展性能，<span lang="EN-US"> Struts</span>是由核心包加上很多工具包构成的，它们已经提供了很多已经实现的功能。因此不要盲目的扩展<span lang="EN-US">Struts</span>框架，要先确定能不能采用其他方法使用现有的功能来实现。 在决定编写扩展代码前务必要确认<span lang="EN-US">Struts</span>的确没有实现你要的功能。否则重复的功能会导致混乱将来还得花费额外的精力清除它。<span lang="EN-US"><br /><br />2. </span>使用异常处理声明<span lang="EN-US"><br /><br /></span>要定义应用程序的逻辑流程，成熟的经验是推荐在代码之外，用配置的方法来实现，而不是写死在程序代码中的。在<span lang="EN-US">J2EE</span>中，这样的例子比比皆是。从实现<span lang="EN-US">EJB</span>的安全性和事务性行为到描述<span lang="EN-US">JMS</span>消息和目的地之间的关系，很多运行时的处理流程都是可以在程序之外定义的。<span lang="EN-US"><br /><br />Struts </span>创建者从一开始就采用这种方法，通过配置<span lang="EN-US">Struts</span>的配置文件来定制应用系统运行时的各个方面。这一点在版本<span lang="EN-US">1.1</span>的新特性上得到延续，包括新的异常处理功能。在<span lang="EN-US">Struts framework</span>以前的版本中，开发人员不得不自己处理<span lang="EN-US">Struts</span>应用中发生的错误情况。在最新的版本中，情况大大的改观了，<span lang="EN-US">Struts Framework</span>提供了内置的一个称为<span lang="EN-US"> ExceptionHandler </span>的类， 用于系统缺省处理<span lang="EN-US">action</span>类运行中产生的错误。这也是在上一个技巧中我们提到的<span lang="EN-US">framework</span>许多可扩展接口之一。<span lang="EN-US"><br /><br />Struts</span>缺省的<span lang="EN-US"> ExceptionHandler</span>类会生成一个<span lang="EN-US">ActionError</span>对象并保存在适当的范围（<span lang="EN-US">scope</span>）对象中。这样就允许<span lang="EN-US">JSP</span>页面使用错误类来提醒用户出现什么问题。如果你认为这不能满足你的需求，那么可以很方便的实现你自己的<span lang="EN-US">ExcepionHandler</span>类。<span lang="EN-US"><br /><br /></span>具体定制异常处理的方法和机制<span lang="EN-US"><br /><br /></span>要定制自己的异常处理机制，第一步是继承<span lang="EN-US">org.apache.struts.action.ExceptionHandler</span>类。这个类有<span lang="EN-US">2</span>个方法可以覆盖，一个是<span lang="EN-US">excute()</span>另外一个是<span lang="EN-US">storeException(). </span>在多数情况下，只需要覆盖其中的<span lang="EN-US">excute()</span>方法。下面是<span lang="EN-US">ExceptionHandler</span>类的<span lang="EN-US">excute()</span>方法声明：<span lang="EN-US"><br /><br /><br /><br /></span>正如你看到的，该方法有好几个参数，其中包括原始的异常。方法返回一个<span lang="EN-US">ActionForward</span>对象，用于异常处理结束后将<span lang="EN-US">controller</span>类带到请求必须转发的地方去。<span lang="EN-US"><br /><br /></span>当然您可以实现任何处理，但一般而言，我们必须检查抛出的异常<span lang="EN-US">,</span>并针对该类型的异常进行特定的处理。缺省的，系统的异常处理功能是创建一个出错信息，同时把请求转发到配置文件中指定的地方去。 定制异常处理的一个常见的例子是处理嵌套异常。假设该异常包含有嵌套异常，这些嵌套异常又包含了其他异常，因此我们必须覆盖原来的<span lang="EN-US">execute()</span>方法，对每个异常编写出错信息。<span lang="EN-US"><br /><br /></span>一旦你创建了自己的<span lang="EN-US">ExceptionHandler </span>类，就应该在<span lang="EN-US">Struts</span>配置文件中的部分声明这个类，以便让<span lang="EN-US">Struts</span>知道改用你自定义的异常处理取代缺省的异常处理<span lang="EN-US">.<br /><br /></span>可以配置你自己的<span lang="EN-US">ExceptionHandler </span>类是用于<span lang="EN-US">Action Mapping</span>特定的部分还是所有的<span lang="EN-US">Action</span>对象。如果是用于<span lang="EN-US">Action Mapping</span>特定的部分就在 元素中配置。如果想让这个类可用于所有的<span lang="EN-US">Action</span>对象<span lang="EN-US">,</span>可以在 元素中指定。例如，假设我们创建了异常处理类<span lang="EN-US">CustomizedExceptionHandler</span>用于所有的<span lang="EN-US">Action</span>类<span lang="EN-US">, </span>元素定义如下所示：<span lang="EN-US"><br /><br /><br /><br /></span>在 元素中可以对很多属性进行设置。在本文中，最重要的属性莫过于<span lang="EN-US">handler</span>属性<span lang="EN-US">, handler</span>属性的值就是自定义的继承了<span lang="EN-US">ExceptionHandler</span>类的子类的全名。 假如该属性没有定义，<span lang="EN-US">Struts</span>会采用自己的缺省值。当然，其他的属性也很重要，但如果想覆盖缺省的异常处理的话，<span lang="EN-US">handler</span>无疑是最重要的属性。<span lang="EN-US"><br /><br /></span>最后必须指出的一点是，你可以有不同的异常处理类来处理不同的异常。在上面的例子中，<span lang="EN-US">CustomizedExceptionHandler</span>用来处理任何<span lang="EN-US">java.lang.Exception</span>的子类<span lang="EN-US">. </span>其实，你也可以定义多个异常处理类，每一个专门处理不同的异常树。下面的<span lang="EN-US">XML</span>片断解释了如何配置以实现这一点。<span lang="EN-US"><br /><br /><br /><br /></span>在这里，一旦有异常抛出，<span lang="EN-US">struts framework</span>将试图在配置文件中找到<span lang="EN-US">ExceptionHandler</span>，如果没有找到，那么<span lang="EN-US">struts</span>将沿着该异常的父类链一层层往上找直到发现匹配的为止。因此，我们可以定义一个层次型的异常处理关系结构，在配置文件中已经体现了这一点。<span lang="EN-US"><br /><br />3. </span>使用应用模块（<span lang="EN-US">Application Modules</span>）<span lang="EN-US"><br /><br />Struts 1.1</span>的一个新特性是应用模块的概念。应用模块允许将单个<span lang="EN-US">Struts</span>应用划分成几个模块，每个模块有自己的<span lang="EN-US">Struts</span>配置文件，<span lang="EN-US">JSP</span>页面，<span lang="EN-US">Action</span>等等。这个新特性是为了解决大中型的开发队伍抱怨最多的一个问题，即为了更好的支持并行开发允许多个配置文件而不是单个配置文件。<span lang="EN-US"><br /><br /></span>注：在早期的<span lang="EN-US">beta</span>版本中，该特性被称为子应用（<span lang="EN-US">sub-applications</span>），最近的改名目的是为了更多地反映它们在逻辑上的分工。<span lang="EN-US"><br /><br /></span>显然，当很多开发人员一起参加一个项目时，单个的<span lang="EN-US">Struts</span>配置文件很容易引起资源冲突。应用模块允许<span lang="EN-US">Struts</span>按照功能要求进行划分，许多情况已经证明这样更贴近实际。例如，假设我们要开发一个典型的商店应用程序。可以将组成部分划分成模块比如<span lang="EN-US">catalog</span>（商品目录）<span lang="EN-US">, customer</span>（顾客）<span lang="EN-US">, customer service</span>（顾客服务）<span lang="EN-US">, order</span>（订单）等。每个模块可以分布到不同的目录下，这样各部分的资源很容易定位，有助于开发和部署。图<span lang="EN-US">1 </span>显示了该应用的目录结构。<span lang="EN-US"><br /><br /></span>图<span lang="EN-US"> 1. </span>一个典型的商店应用程序的目录结构<span lang="EN-US"><br /><?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /?><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></v:path><o:lock v:ext="edit" aspectratio="t"></o:lock></v:shapetype><v:shape id="_x0000_i1025" style="WIDTH: 117pt; HEIGHT: 181.5pt" type="#_x0000_t75" alt=""><v:imagedata src="file:///C:\DOCUME~1\SKY_WI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.jpg" o:href="http://www.uml.org.cn/j2ee/images/jakarta1.jpg"></v:imagedata></v:shape><br /></span>注：如果你无需将项目划分成多个模块，<span lang="EN-US">Struts</span>框架支持一个缺省的应用模块。这就使得应用程序也可以在<span lang="EN-US">1.0</span>版本下创建，具有可移植性，因为应用程序会自动作为缺省的应用模块。<span lang="EN-US"><br /><br /></span>为了使用多应用模块功能，必须执行以下几个准备步骤：<span lang="EN-US"><br /><br />• </span>为每个应用模块创建独立的<span lang="EN-US">Struts</span>配置文件。<span lang="EN-US"><br /><br />• </span>配置<span lang="EN-US">Web </span>部署描述符<span lang="EN-US"> Web.xml</span>文件。<span lang="EN-US"><br /><br />• </span>使用<span lang="EN-US">org.apache.struts.actions.SwitchAction </span>来实现程序在模块之间的跳转<span lang="EN-US">.<br /><br /></span>创建独立的<span lang="EN-US">Struts</span>配置文件<span lang="EN-US"><br /><br /></span>每个<span lang="EN-US">Struts</span>应用模块必须拥有自己的配置文件。允许创建自己的独立于其他模块的<span lang="EN-US">Action</span>，<span lang="EN-US">ActionForm</span>，异常处理甚至更多。<span lang="EN-US"><br /><br /></span>继续以上面的商店应用程序为例，我们可以创建以下的配置文件：一个文件名为<span lang="EN-US">struts-config-catalog.xml</span>，包含<span lang="EN-US">catalog</span>（商品目录）、<span lang="EN-US">items(</span>商品清单<span lang="EN-US">)</span>、和其它与库存相关的功能的配置信息；另一个文件名为<span lang="EN-US">struts- config-order.xml, </span>包含对<span lang="EN-US">order</span>（订单）和<span lang="EN-US">order tracking</span>（订单跟踪）的设置。第三个配置文件是<span lang="EN-US">struts-config.xml,</span>其中含有属于缺省的应用模块中的一般性的功能。<span lang="EN-US"><br /><br /></span>配置<span lang="EN-US">Web</span>部署描述符<span lang="EN-US"><br /><br /></span>在<span lang="EN-US">Struts</span>的早期版本中，我们在<span lang="EN-US">Web.xml</span>中指定<span lang="EN-US">Struts</span>配置文件的路径。好在这点没变，有助于向后兼容。但对于多个应用模块，我们需要在<span lang="EN-US">Web</span>部署描述符中增加新的配置文件的设定。<span lang="EN-US"><br /><br /></span>对于缺省的应用（包括<span lang="EN-US">Struts</span>的早期版本），<span lang="EN-US">Struts framework </span>在<span lang="EN-US">Web.xml</span>文件中查找带有<span lang="EN-US">config</span>的元素 ，用于载入<span lang="EN-US">Action mapping </span>和其它的应用程序设定。作为例子，以下的<span lang="EN-US">XML</span>片断展现一个典型的 元素：<span lang="EN-US"><br /><br /><br /><br /></span>注：如果在现有的 元素中找不到<span lang="EN-US">"config"</span>关键字，<span lang="EN-US">Struts framework</span>将缺省地使用<span lang="EN-US">/WEB/struts-config.xml<br /><br /></span>为了支持多个应用模块<span lang="EN-US">(Struts 1.1</span>的新特性<span lang="EN-US">)</span>，必须增加附加的 元素。与缺省的 元素不同的是，附加的 元素与每个应用模块对应，必须以<span lang="EN-US">config/xxx</span>的形式命名，其中字符串<span lang="EN-US">xxx</span>代表该模块唯一的名字。例如，在商店应用程序的例子中， 元素可定义如下（注意粗体字部分）：<span lang="EN-US"><br /><br /></span>第一个 元素对应缺省的应用模块。第二和第三个元素分别代表非缺省应用模块<span lang="EN-US">catalog </span>和<span lang="EN-US"> order</span>。<span lang="EN-US"><br /><br /></span>当<span lang="EN-US">Struts</span>载入应用程序时，它首先载入缺省应用模块的配置文件。然后查找带有字符串<span lang="EN-US">config/xxx </span>形式的附加的初始化参数。对每个附加的配置文件也进行解析并载入内存。这一步完成后，用户就可以很随意地用<span lang="EN-US">config/</span>后面的字符串也就是名字来调用相应的应用模块。<span lang="EN-US"><br /><br /></span>多个应用模块之间调用<span lang="EN-US">Action</span>类<span lang="EN-US"><br /><br /></span>在为每个应用模块创建独立的配置文件之后，我们就有可能需要调用不同的模块中<span lang="EN-US">Action</span>。为此必须使用<span lang="EN-US">Struts</span>框架提供的<span lang="EN-US">SwitchAction</span>类。<span lang="EN-US">Struts </span>会自动将应用模块的名字添加到<span lang="EN-US">URL,</span>就如<span lang="EN-US">Struts </span>自动添加应用程序的名字加到<span lang="EN-US">URL</span>一样。应用模块是对框架的一个新的扩充，有助于进行并行的团队开发。如果你的团队很小那就没必要用到这个特性，不必进行模块化。当然，就算是只有一个模块，系统还是一样的运作。<span lang="EN-US"><br /><br />4. </span>把<span lang="EN-US">JSP</span>放到<span lang="EN-US">WEB-INF</span>后以保护<span lang="EN-US">JSP</span>源代码<span lang="EN-US"><br /><br /></span>为了更好地保护你的<span lang="EN-US">JSP</span>避免未经授权的访问和窥视， 一个好办法是将页面文件存放在<span lang="EN-US">Web</span>应用的<span lang="EN-US">WEB-INF</span>目录下。<span lang="EN-US"><br /><br /></span>通常<span lang="EN-US">JSP</span>开发人员会把他们的页面文件存放在<span lang="EN-US">Web</span>应用相应的子目录下。一个典型的商店应用程序的目录结构如图<span lang="EN-US">2</span>所示。跟<span lang="EN-US">catalog </span>（商品目录）相关的<span lang="EN-US">JSP</span>被保存在<span lang="EN-US">catalog</span>子目录下。跟<span lang="EN-US">customer</span>相关的<span lang="EN-US">JSP</span>，跟订单相关的<span lang="EN-US">JSP</span>等都按照这种方法存放。<span lang="EN-US"><br /><br /><br /><br /></span>图<span lang="EN-US"> 2.</span>基于不同的功能<span lang="EN-US"> JSP </span>被放置在不同的目录下<span lang="EN-US"><br /><v:shape id="_x0000_i1026" style="WIDTH: 117pt; HEIGHT: 181.5pt" type="#_x0000_t75" alt=""><v:imagedata src="file:///C:\DOCUME~1\SKY_WI~1\LOCALS~1\Temp\msohtml1\01\clip_image002.jpg" o:href="http://www.uml.org.cn/j2ee/images/jakarta2.jpg"></v:imagedata></v:shape><br /></span>这种方法的问题是这些页面文件容易被偷看到源代码，或被直接调用。某些场合下这可能不是个大问题，可是在特定情形中却可能构成安全隐患。用户可以绕过<span lang="EN-US">Struts</span>的<span lang="EN-US">controller</span>直接调用<span lang="EN-US">JSP</span>同样也是个问题。<span lang="EN-US"><br /><br /></span>为了减少风险，可以把这些页面文件移到<span lang="EN-US">WEB-INF </span>目录下。基于<span lang="EN-US">Servlet</span>的声明，<span lang="EN-US">WEB-INF</span>不作为<span lang="EN-US">Web</span>应用的公共文档树的一部分。因此，<span lang="EN-US">WEB-INF </span>目录下的资源不是为客户直接服务的。我们仍然可以使用<span lang="EN-US">WEB-INF</span>目录下的<span lang="EN-US">JSP</span>页面来提供视图给客户，客户却不能直接请求访问<span lang="EN-US">JSP</span>。<span lang="EN-US"><br /><br /></span>采用前面的例子，图<span lang="EN-US">3</span>显示将<span lang="EN-US">JSP</span>页面移到<span lang="EN-US">WEB-INF </span>目录下后的目录结构<span lang="EN-US"><br /><br /></span>图<span lang="EN-US"> 3. JSP</span>存放在<span lang="EN-US"> WEB-INF </span>目录下更为安全<span lang="EN-US"><br /><v:shape id="_x0000_i1027" style="WIDTH: 111.75pt; HEIGHT: 177.75pt" type="#_x0000_t75" alt=""><v:imagedata src="file:///C:\DOCUME~1\SKY_WI~1\LOCALS~1\Temp\msohtml1\01\clip_image003.jpg" o:href="http://www.uml.org.cn/j2ee/images/jakarta3.jpg"></v:imagedata></v:shape><br /></span>如果把这些<span lang="EN-US">JSP</span>页面文件移到<span lang="EN-US">WEB-INF </span>目录下，在调用页面的时候就必须把<span lang="EN-US">"WEB-INF"</span>添加到<span lang="EN-US">URL</span>中。例如，在一个<span lang="EN-US">Struts</span>配置文件中为一个<span lang="EN-US">logoff action</span>写一个<span lang="EN-US">Action mapping</span>。其中<span lang="EN-US">JSP</span>的路径必须以<span lang="EN-US">"WEB-INF"</span>开头。如下所示：请注意粗体部分<span lang="EN-US">.<br /><br /></span>这个方法在任何情况下都不失为<span lang="EN-US">Struts</span>实践中的一个好方法。是唯一要注意的技巧是你必须把<span lang="EN-US">JSP</span>和一个<span lang="EN-US">Struts action</span>联系起来。即使该<span lang="EN-US">Action</span>只是一个很基本的很简单<span lang="EN-US">JSP</span>，也总是要调用一个<span lang="EN-US">Action</span>，再由它调用<span lang="EN-US">JSP</span>。<span lang="EN-US"><br /><br /></span>最后要说明的是，并不是所有的容器都能支持这个特性。<span lang="EN-US">WebLogic</span>早期的版本不能解释<span lang="EN-US">Servlet</span>声明，因此无法提供支持，据报道在新版本中已经改进了。总之使用之前先检查一下你的<span lang="EN-US">Servlet</span>容器。<span lang="EN-US"><br /><br />5. </span>使用<span lang="EN-US"> Prebuilt Action</span>类提升开发效率<span lang="EN-US"><br /><br />Struts framework</span>带有好几个<span lang="EN-US">prebuilt Action</span>类，使用它们可以大大节省开发时间。其中最有用的是<span lang="EN-US">org.apache.struts.actions.ForwardAction </span>和<span lang="EN-US"> org.apache.struts.actions.DispatchAction.<br /><br /></span>使用<span lang="EN-US"> ForwardAction<br /><br /></span>在应用程序中，可能会经常出现只要将<span lang="EN-US">Action</span>对象转发到某个<span lang="EN-US">JSP</span>的情况。在上一点中曾提到总是由<span lang="EN-US">Action</span>调用<span lang="EN-US">JSP</span>是个好习惯。如果我们不必在<span lang="EN-US">Action</span>中执行任何业务逻辑，却又想遵循从<span lang="EN-US">Action</span>访问页面的话，就可以使用<span lang="EN-US">ForwardAction</span>，它可以使你免去创建许多空的<span lang="EN-US">Action</span>类。运用<span lang="EN-US">ForwardAction</span>的好处是不必创建自己的<span lang="EN-US">Action</span>类，你需要做的仅仅是在<span lang="EN-US">Struts</span>配置文件中配置一个<span lang="EN-US">Action mapping</span>。<span lang="EN-US"><br /><br /></span>举个例子，假定你有一个<span lang="EN-US">JSP</span>文件<span lang="EN-US">index.jsp </span>，而且不能直接调用该页面，必须让程序通过一个<span lang="EN-US">Action</span>类调用，那么，你可以建立以下的<span lang="EN-US">Action mapping</span>来实现这一点：<span lang="EN-US"><br /><br /></span>正如你看到的，当<span lang="EN-US"> /home </span>被调用时<span lang="EN-US">, </span>就会调用<span lang="EN-US">ForwardAction </span>并把请求转发到<span lang="EN-US"> index.jsp </span>页面<span lang="EN-US">.<br /><br /></span>再讨论一下不通过一个<span lang="EN-US">Action</span>类直接转发到某个页面的情况，必须注意我们仍然使用 元素中的<span lang="EN-US">forward</span>属性来实现转发的目标。这时 元素定义如下：<span lang="EN-US"><br /><br /></span>以上两种方法都可以节省你的时间，并有助于减少一个应用所需的文件数。<span lang="EN-US"><br /><br /></span>使用<span lang="EN-US"> DispatchAction<br /><br />DispatchAction</span>是<span lang="EN-US">Struts</span>包含的另一个能大量节省开发时间的<span lang="EN-US">Action</span>类。与其它<span lang="EN-US">Action</span>类仅提供单个<span lang="EN-US">execute()</span>方法实现单个业务不同，<span lang="EN-US">DispatchAction</span>允许你在单个<span lang="EN-US">Action</span>类中编写多个与业务相关的方法。这样可以减少<span lang="EN-US">Action</span>类的数量，并且把相关的业务方法集合在一起使得维护起来更容易。<span lang="EN-US"><br /><br /></span>要使用<span lang="EN-US">DispatchAction</span>的功能，需要自己创建一个类，通过继承抽象的<span lang="EN-US">DispatchAction</span>得到。对每个要提供的业务方法必须有特定的方法<span lang="EN-US">signature</span>。例如，我们想要提供一个方法来实现对购物车添加商品清单，创建了一个类<span lang="EN-US">ShoppingCartDispatchAction</span>提供以下的方法：<span lang="EN-US"><br /><br /></span>那么，这个类很可能还需要一个<span lang="EN-US">deleteItem()</span>方法从客户的购物车中删除商品清单，还有<span lang="EN-US">clearCart()</span>方法清除购物车等等。这时我们就可以把这些方法集合在单个<span lang="EN-US">Action</span>类，不用为每个方法都提供一个<span lang="EN-US">Action</span>类。<span lang="EN-US"><br /><br /></span>在调用<span lang="EN-US">ShoppingCartDispatchAction</span>里的某个方法时，只需在<span lang="EN-US">URL</span>中提供方法名作为参数值。就是说，调用<span lang="EN-US">addItem()</span>方法的 <span lang="EN-US">URL</span>看起来可能类似于：<span lang="EN-US"><br /><br />http://myhost/storefront/action/cart?method=addItem<br /><br /></span>其中<span lang="EN-US">method</span>参数指定<span lang="EN-US">ShoppingCartDispatchAction</span>中要调用的方法。参数的名称可以任意配置，这里使用的<span lang="EN-US">"method"</span>只是一个例子。参数的名称可以在<span lang="EN-US">Struts</span>配置文件中自行设定。<span lang="EN-US"><br /><br />6.</span>使用动态<span lang="EN-US">ActionForm<br /><br /></span>在<span lang="EN-US">Struts framework</span>中，<span lang="EN-US">ActionForm</span>对象用来包装<span lang="EN-US">HTML</span>表格数据（包括请求），并返回返回动态显示给用户的数据。它们必须是完全的<span lang="EN-US">JavaBean</span>，并继承<span lang="EN-US">.Struts</span>　里面的<span lang="EN-US">ActionForm</span>类，同时，用户可以有选择地覆盖两个缺省方法。<span lang="EN-US"><br /><br /></span>该特性能节省很多时间，因为它可以协助进行自动的表现层的验证。<span lang="EN-US">ActionForm</span>的唯一缺点是必须为不同的<span lang="EN-US">HTML</span>表格生成多个<span lang="EN-US">ActionForm </span>类以保存数据。例如，如果有一个页面含有用户的注册信息，另一个页面则含有用户的介绍人的信息，那么就需要有两个不同的<span lang="EN-US">ActionForm</span>类。这在大的应用系统中就会导致过多的<span lang="EN-US">ActionForm</span>类。<span lang="EN-US">Struts 1.1</span>对此做出了很好的改进，引入了动态<span lang="EN-US">ActionForm</span>类概念<span lang="EN-US"><br /><br /></span>通过<span lang="EN-US">Struts framework</span>中的<span lang="EN-US">DynaActionForm</span>类及其子类可以实现动态的<span lang="EN-US">ActionForm </span>，动态的<span lang="EN-US">ActionForm</span>允许你通过<span lang="EN-US">Struts</span>的配置文件完成<span lang="EN-US">ActionForm</span>的全部配置；再也没有必要在应用程序中创建具体的<span lang="EN-US">ActionForm</span>类。具体配置方法是：在<span lang="EN-US">Struts</span>的配置文件通过增加一个 元素，将<span lang="EN-US">type</span>属性设定成<span lang="EN-US">DynaActionForm</span>或它的某个子类的全名。下面的例子创建了一个动态的<span lang="EN-US">ActionForm</span>名为<span lang="EN-US">logonForm</span>，它包含两个实例变量：<span lang="EN-US">username </span>和<span lang="EN-US"> password.<br /><br /><br /><br /></span>动态的<span lang="EN-US">ActionForm</span>可以用于<span lang="EN-US">Action</span>类和<span lang="EN-US">JSP</span>，使用方法跟普通的<span lang="EN-US">ActionForm</span>相同，只有一个小差别。如果使用普通的<span lang="EN-US">ActionForm</span>对象则需要提供<span lang="EN-US">get </span>和<span lang="EN-US"> set</span>方法取得和设置数据。以上面的例子而言，我们需要提供<span lang="EN-US">getUsername() </span>和<span lang="EN-US"> setUsername()</span>方法取得和设置<span lang="EN-US">username</span>变量，同样地有一对方法用于取得和设置<span lang="EN-US">password</span>变量<span lang="EN-US">.<br /><br /></span>这里我们使用的是<span lang="EN-US">DynaActionForm</span>，它将变量保存在一个<span lang="EN-US">Map</span>类对象中，所以必须使用<span lang="EN-US">DynaActionForm </span>类中的<span lang="EN-US">get(name) </span>和<span lang="EN-US"> set(name)</span>方法，其中参数<span lang="EN-US">name</span>是要访问的实例变量名。例如要访问<span lang="EN-US">DynaActionForm</span>中<span lang="EN-US">username</span>的值，可以采用类似的代码：<span lang="EN-US"><br /><br />String username = (String)form.get("username");<br /><br /></span>由于值存放在一个<span lang="EN-US">Map</span>对象，所以要记得对<span lang="EN-US">get()</span>方法返回的<span lang="EN-US">Object</span>对象做强制性类型转换。<span lang="EN-US"><br /><br />DynaActionForm</span>有好几个很有用的子类。其中最重要的是<span lang="EN-US">DynaValidatorForm </span>，这个动态的<span lang="EN-US">ActionForm</span>和<span lang="EN-US">Validator </span>一起利用公共的<span lang="EN-US">Validator</span>包来提供自动验证。这个特性使你得以在程序代码之外指定验证规则。将两个特性结合使用对开发人员来说将非常有吸引力。<span lang="EN-US"><br /><br />7. </span>使用可视化工具<span lang="EN-US"><br /><br /></span>自从<span lang="EN-US">Struts 1.0 </span>分布以来，就出现了不少可视化工具用于协助创建，修改和维护<span lang="EN-US">Struts</span>的配置文件。配置文件本身是基于<span lang="EN-US">XML</span>格式，在大中型的开发应用中会增大变得很笨拙。为了更方便的管理这些文件，一旦文件大到你无法一目了然的时候，建议试着采用其中的一种<span lang="EN-US">GUI </span>工具协助开发。商业性的和开放源代码的工具都有不少，表<span lang="EN-US">1</span>列出了可用的工具和其相关链接，从那里可以获取更多信息。<span lang="EN-US"><br /><br /></span>表<span lang="EN-US"> 1. Struts GUI </span>工具<span lang="EN-US"><br /></span>应用程序 性质 网址<span lang="EN-US"><br />Adalon </span>商业软件<span lang="EN-US"> http://www.synthis.com/products/adalon<br />Easy Struts </span>开放源码<span lang="EN-US"> http://easystruts.sourceforge.net/<br />Struts Console </span>免费<span lang="EN-US"> http://www.jamesholmes.com/struts/console<br />JForms </span>商业软件 <span lang="EN-US">http://www.solanasoft.com/<br />Camino </span>商业软件<span lang="EN-US"> http://www.scioworks.com/scioworks_camino.html<br />Struts Builder </span>开放源码<span lang="EN-US"> http://sourceforge.net/projects/rivernorth/<br />StrutsGUI </span>免费<span lang="EN-US"> http://www.alien-factory.co.uk/struts/struts-index.html<o:p></o:p></span></span>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/SkyWinder/aggbug/60815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/SkyWinder/" target="_blank">枫中玎玲</a> 2006-07-30 09:13 <a href="http://www.blogjava.net/SkyWinder/archive/2006/07/30/60815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>