??xml version="1.0" encoding="utf-8" standalone="yes"?>
执行操作 T—SQL语句
创徏数据?CREATE DATABASE 数据库名
删除数据?DROP DATABASE 数据库名
创徏?CREATE TABLE 表名
删除?DROP TABLE 表名
修改表的字段cd ALTER TABLE 表名 ALTER COLUMN 字段?nbsp; 数据cd
向表中添加新的字D?ALTER TABLE 表名 ADD 字段?nbsp; 数据cd
删除表中原有字段 ALTER TABLE 表名 DROP COLUMN 字段?
向已有表中添加主?ALTER TABLE 表名 ADD CONSTRAINT U束?nbsp;PRIMARY KEY (主键字段?
向已有表中添加外?ALTER TABLE 表名 ADD CONSTRAINT U束?nbsp;FOREIGN KEY (外键字段
? REFERENCES 主键表名Q主键字D名Q?
删除表中已有U束Qalter table 表名 drop constraint U束?br />
向已有表中添加默认?ALTER TABLE 表名 ADD CONSTRAINT U束?nbsp;DEFAULT 默认?nbsp;FOR d默认值的字段?
向已有表中添加检查约?ALTER TABLE 表名 ADD CONSTRAINT U束名_CHECK CHECEK (查约束表辑ּ)
向已有表中添加惟一?ALTER TABLE 表名 ADD CONSTRAINT U束?nbsp;UNIQUEQ添加惟一性的字段名)
向表中添加数?INSERT INTO 表名 valueS (向表中添加的记录)
把表A中数据拷贝到表B?INSERT INTO 表B?nbsp; SELECT 字段?nbsp;FROM 表A?
更新表中所有记录数?UPDATE 表名 SET 数据更新表达?
更新一个或部分记录 UPDATE 表名 SET 数据更新表达?nbsp;WHERE 选择数据的条?
删除表中全部记录 DELETE FROM 表名 TRUNCATE TABLE 表名
删除部分记录 DELETE FROM 表名 WHERE 记录选择条g
按条件查询表中记?nbsp; SELECT 字段?nbsp;FROM 表名 WHERE 查询条g
使用ORDER BY子句 SELECT 字段?nbsp;FROM 表名 ORDER BY 排序字段?nbsp;SELECT 字段?nbsp;FROM 表名 ORDER BY 排序字段?nbsp;DESC
使用AS子句 SELECT 字段?nbsp;AS l果昄时的字段?nbsp; FROM 表名
使用TOP子句 SELECT TOP N 字段?nbsp;FROM 表名 SELECT TOP N PERCENT 字段?nbsp;FROM 表名
SUM函数 SELECT SUM (字段? FROM 表名
AVG函数 SELECT AVG (字段? FROM 表名
COUNT函数 SELECT COUNT (字段? FROM 表名
MAX函数 SELECT MAX (字段? FROM 表名
MIN函数 SELECT MIN (字段? FROM 表名
使用GROUP BY子句 SELECT 字段?nbsp;FROM 表名 GROUP BY 分组字段?
使用HAVING子句 SELECT 字段?nbsp;FROM 表名 WHERE 查询条g GROUP BY 分组字段?nbsp; HAVING 分组条g
LIKE通配W?SELECT 字段?nbsp;FROM 表名 WHERE 字段?nbsp;LIKE 条g
IN 通配W?SELECT 字段?nbsp;FROM 表名 WHERE 字段?nbsp;IN (?
BETWEEN通配W?SELECT 字段?nbsp;FROM 表名 WHERE 字段?nbsp;BETWEEN ? AND ?
IS NULL 通配W?SELECT 字段?nbsp;FROM 表名 WHERE 字段?nbsp;IS NULL
]]>
1.书写格式
CZ代码Q?/p>
存储q程SQL文书写格式例
select
c.dealerCode,
round(sum(c.submitSubletAmountDLR + c.submitPartsAmountDLR + c.submitLaborAmountDLR) / count(*), 2) as avg,
decode(null, 'x', 'xx', 'CNY')
from (
select
a.dealerCode,
a.submitSubletAmountDLR,
a.submitPartsAmountDLR,
a.submitLaborAmountDLR
from SRV_TWC_F a
where (to_char(a.ORIGSUBMITTIME, 'yyyy/mm/dd') >= 'Date Range(start)'
and to_char(a.ORIGSUBMITTIME, 'yyyy/mm/dd') <= 'Date Range(end)'
and nvl(a.deleteflag, '0') <> '1')
union all
select
b.dealerCode,
b.submitSubletAmountDLR,
b.submitPartsAmountDLR,
b.submitLaborAmountDLR
from SRV_TWCHistory_F b
where (to_char(b.ORIGSUBMITTIME, 'yyyy/mm/dd') >= 'Date Range(start)'
and to_char(b.ORIGSUBMITTIME,'yyyy/mm/dd') <= 'Date Range(end)'
and nvl(b.deleteflag,'0') <> '1')
) c
group by c.dealerCode
order by avg desc;
Java source里的SQL字符串书写格式例
strSQL = "insert into Snd_FinanceHistory_Tb "
+ "(DEALERCODE, "
+ "REQUESTSEQUECE, "
+ "HANDLETIME, "
+ "JOBFLAG, "
+ "FRAMENO, "
+ "INMONEY, "
+ "REMAINMONEY, "
+ "DELETEFLAG, "
+ "UPDATECOUNT, "
+ "CREUSER, "
+ "CREDATE, "
+ "HONORCHECKNO, "
+ "SEQ) "
+ "values ('" + draftInputDetail.dealerCode + "', "
+ "'" + draftInputDetail.requestsequece + "', "
+ "sysdate, "
+ "'07', "
+ "'" + frameNO + "', "
+ requestMoney + ", "
+ remainMoney + ", "
+ "'0', "
+ "0, "
+ "'" + draftStruct.employeeCode + "', "
+ "sysdate, "
+ "'" + draftInputDetail.honorCheckNo + "', "
+ index + ")";
1).~进
对于存储q程文gQ羃qؓ8个空?br />
对于Java source里的SQL字符Ԍ不可有羃q,x一行字W串不可以空格开?/p>
2).换行
1>.Select/From/Where/Order by/Group by{子句必d其一行写
2>.Select子句内容如果只有一,与Select同行?br />
3>.Select子句内容如果多于一,每一单独占一行,在对应Select的基上向右羃q?个空|Java source无羃q)
4>.From子句内容如果只有一,与From同行?br />
5>.From子句内容如果多于一,每一单独占一行,在对应From的基上向右羃q?个空|Java source无羃q)
6>.Where子句的条件如果有多项Q每一个条件占一行,以AND开_且无~进
7>.(Update)Set子句内容每一单独占一行,无羃q?br />
8>.Insert子句内容每个表字D单独占一行,无羃q;values每一单独占一行,无羃q?br />
9>.SQL文中间不允许出现I
10>.Java source里单引号必须跟所属的SQL子句处在同一行,q接W("+"Q必d行首
3).I格
1>.SQL内算数运符、逻辑q算W连接的两个元素之间必须用空格分?br />
2>.逗号之后必须接一个空?br />
3>.关键字、保留字和左括号之间必须有一个空?/p>
2.不等于统一使用"<>"
Oracle认ؓ"!="?<>"是等LQ都代表不等于的意义。ؓ了统一Q不{于一律?<>"表示
3.使用表的别名
数据库查询,必须使用表的别名
4.SQL文对表字D|展的兼容?br /> 在Java source里用Select *Ӟ严禁通过getString(1)的Ş式得到查询结果,必须使用getString("字段?)的Ş?br /> 使用InsertӞ必须指定插入的字D名Q严不指定字段名直接插入values
5.减少子查询的使用
子查询除了可L差之外Q还在一定程度上影响了SQLq行效率
请尽量减用子查询的用,用其他效率更高、可L更好的方式替代
6.适当d索引以提高查询效?br />
适当d索引可以大幅度的提高索速度
请参看ORACLE SQL性能优化pd
7.Ҏ据库表操作的Ҏ要求
本项目对数据库表的操作还有以下特D要求:
1).以逻辑删除替代物理删除
注意Q现在数据库表中数据没有物理删除Q只有逻辑删除
以deleteflag字段作ؓ删除标志Qdeleteflag='1'代表此记录被逻辑删除Q因此在查询数据时必考虑deleteflag的因?br />
deleteflag的标准查询条ӞNVL(deleteflag, '0') <> '1'
2).增加记录状态字D?br />
数据库中的每张表基本都有以下字段QDELETEFLAG、UPDATECOUNT、CREDATE、CREUSER、UPDATETIME、UPDATEUSER
要注意在Ҏq行操作时必考虑以下字段
插入一条记录时要置DELETEFLAG='0', UPDATECOUNT=0, CREDATE=sysdate, CREUSER=dUser
查询一条记录时要考虑DELETEFLAGQ如果有可能Ҏ记录作更新时q要取得UPDATECOUNT作同步检?br />
修改一条记录时要置UPDATETIME=sysdate, UPDATEUSER=dUser, UPDATECOUNT=(UPDATECOUNT+1) mod 1000,
删除一条记录时要置DELETEFLAG='1'
3).历史?br />
数据库里部分表还存在相应的历史表Q比如srv_twc_f和srv_twchistory_f
在查询数据时除了索所在表之外Q还必须索相应的历史表,对二者的l果做UnionQ或Union AllQ?/p>
8.用执行计划分析SQL性能
EXPLAIN PLAN是一个很好的分析SQL语句的工P它可以在不执行SQL的情况下分析语句
通过分析Q我们就可以知道ORACLE是怎样q接表,使用什么方式扫描表Q烦引扫描或全表扫描Q,以及使用到的索引名称
按照从里到外Q从上到下的ơ序解读分析的结?br /> EXPLAIN PLAN的分析结果是用羃q的格式排列的,最内部的操作将最先被解读Q如果两个操作处于同一层中Q带有最操作号的将首先被执?/p>
目前许多W三方的工具如PLSQL Developer和TOAD{都提供了极其方便的EXPLAIN PLAN工具
PG需要将自己d的查询SQL文记入logQ然后在EXPLAIN PLAN中进行分析,量减少全表扫描
ORACLE SQL性能优化pd
1.选择最有效率的表名序(只在Z规则的优化器中有?
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名Q因此FROM子句中写在最后的表(基础表driving tableQ将被最先处?br />
在FROM子句中包含多个表的情况下Q必选择记录条数最的表作为基?br />
当ORACLE处理多个表时Q会q用排序及合q的方式q接它们
首先Q扫描第一个表QFROM子句中最后的那个?q对记录q行排序Q?br />
然后扫描W二个表QFROM子句中最后第二个?Q?br />
最后将所有从W二个表中检索出的记录与W一个表中合适记录进行合q?br />
例如:
?TAB1 16,384 条记?br />
?TAB2 5 条记?br />
选择TAB2作ؓ基础?(最好的Ҏ)
select count(*) from tab1,tab2 执行旉0.96U?
选择TAB2作ؓ基础?(不佳的方?
select count(*) from tab2,tab1 执行旉26.09U?
如果?个以上的表连接查询,那就需要选择交叉表(intersection tableQ作为基表,交叉表是指那个被其他表所引用的表
例如:
EMP表描qCLOCATION表和CATEGORY表的交集
SELECT *
FROM LOCATION L,
CATEGORY C,
EMP E
WHERE E.EMP_NO BETWEEN 1000 AND 2000
AND E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
比下列SQL更有效率
SELECT *
FROM EMP E ,
LOCATION L ,
CATEGORY C
WHERE E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
AND E.EMP_NO BETWEEN 1000 AND 2000
2.WHERE子句中的q接序
ORACLE采用自下而上的顺序解析WHERE子句
Ҏq个原理Q表之间的连接必d在其他WHERE条g之前Q那些可以过滤掉最大数量记录的条g必须写在WHERE子句的末?br />
例如Q?br />
(低效,执行旉156.3U?
SELECT *
FROM EMP E
WHERE SAL > 50000
AND JOB = 'MANAGER'
AND 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO);
(高效,执行旉10.6U?
SELECT *
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO)
AND SAL > 50000
AND JOB = 'MANAGER';
3.SELECT子句中避免?*'
当你惛_SELECT子句中列出所有的COLUMNӞ使用动态SQL列引?*'是一个方便的ҎQ不q的是,q是一个非怽效的Ҏ
实际上,ORACLE在解析的q程中,会将'*'依次转换成所有的列名
q个工作是通过查询数据字典完成的,q意味着耗费更多的时?/p>
4.减少讉K数据库的ơ数
当执行每条SQL语句ӞORACLE在内部执行了许多工作Q解析SQL语句Q估烦引的利用率,l定变量Q读数据块等{?br />
由此可见Q减访问数据库的次敎ͼp实际上减ORACLE的工作量
例如Q?br />
以下有三U方法可以检索出雇员L?342?291的职?br />
Ҏ1 (最低效)
SELECT EMP_NAME, SALARY, GRADE
FROM EMP
WHERE EMP_NO = 342;
SELECT EMP_NAME, SALARY, GRADE
FROM EMP
WHERE EMP_NO = 291;
Ҏ2 (ơ低?
DECLARE
CURSOR C1 (E_NO NUMBER) IS
SELECT EMP_NAME,SALARY,GRADE
FROM EMP
WHERE EMP_NO = E_NO;
BEGIN
OPEN C1(342);
FETCH C1 INTO …,…,…;
…
OPEN C1(291);
FETCH C1 INTO …,…,…;
…
CLOSE C1;
END;
Ҏ2 (高效)
SELECT A.EMP_NAME, A.SALARY, A.GRADE,
B.EMP_NAME, B.SALARY, B.GRADE
FROM EMP A, EMP B
WHERE A.EMP_NO = 342
AND B.EMP_NO = 291;
5.使用DECODE函数来减处理时?br />
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的?br />
例如Q?br />
SELECT COUNT(*), SUM(SAL)
FROM EMP
WHERE DEPT_NO = '0020'
AND ENAME LIKE 'SMITH%';
SELECT COUNT(*), SUM(SAL)
FROM EMP
WHERE DEPT_NO = '0030'
AND ENAME LIKE 'SMITH%';
你可以用DECODE函数高效地得到相同结?br />
SELECT COUNT(DECODE(DEPT_NO, '0020', 'X', NULL)) D0020_COUNT,
COUNT(DECODE(DEPT_NO, '0030', 'X', NULL)) D0030_COUNT,
SUM(DECODE(DEPT_NO, '0020', SAL, NULL)) D0020_SAL,
SUM(DECODE(DEPT_NO, 0030, SAL, NULL)) D0030_SAL
FROM EMP
WHERE ENAME LIKE 'SMITH%';
'X'表示M一个字D?br /> cM的,DECODE函数也可以运用于GROUP BY和ORDER BY子句?
6.用Where子句替换HAVING子句
避免使用HAVING子句QHAVING只会在检索出所有记录之后才对结果集q行qoQ这个处理需要排序、统计等操作
如果能通过WHERE子句限制记录的数目,那就能减这斚w的开销
例如Q?br />
低效
SELECT REGION, AVG(LOG_SIZE)
FROM LOCATION
GROUP BY REGION
HAVING REGION REGION != 'SYDNEY'
AND REGION != 'PERTH'
高效
SELECT REGION, AVG(LOG_SIZE)
FROM LOCATION
WHERE REGION REGION != 'SYDNEY'
AND REGION != 'PERTH'
GROUP BY REGION
7.减少对表的查?br />
在含有子查询的SQL语句中,要特别注意减对表的查询
例如Q?br />
低效
SELECT TAB_NAME
FROM TABLES
WHERE TAB_NAME = (SELECT TAB_NAME
FROM TAB_COLUMNS
WHERE VERSION = 604)
AND DB_VER = (SELECT DB_VER
FROM TAB_COLUMNS
WHERE VERSION = 604)
高效
SELECT TAB_NAME
FROM TABLES
WHERE (TAB_NAME, DB_VER) = (SELECT TAB_NAME, DB_VER
FROM TAB_COLUMNS
WHERE VERSION = 604)
Update多个Column例子Q?br />
低效
UPDATE EMP
SET EMP_CAT = (SELECT MAX(CATEGORY)
FROM EMP_CATEGORIES),
SAL_RANGE = (SELECT MAX(SAL_RANGE)
FROM EMP_CATEGORIES)
WHERE EMP_DEPT = 0020;
高效
UPDATE EMP
SET (EMP_CAT, SAL_RANGE) = (SELECT MAX(CATEGORY), MAX(SAL_RANGE)
FROM EMP_CATEGORIES)
WHERE EMP_DEPT = 0020;
8.使用表的别名(Alias)
当在SQL语句中连接多个表Ӟ请用表的别名ƈ把别名前~于每个Column?br />
q样可以减少解析的时间ƈ减少那些由Column歧义引v的语法错?/p>
9.用EXISTS替代IN
在许多基于基表的查询中,Z满一个条Ӟ往往需要对另一个表q行联接
在这U情况下Q用EXISTS(或NOT EXISTS)通常提高查询的效率
低效
SELECT *
FROM EMP (基础?
WHERE EMPNO > 0
AND DEPTNO IN (SELECT DEPTNO
FROM DEPT
WHERE LOC = 'MELB')
高效
SELECT *
FROM EMP (基础?
WHERE EMPNO > 0
AND EXISTS (SELECT 'X'
FROM DEPT
WHERE DEPT.DEPTNO = EMP.DEPTNO
AND LOC = 'MELB')
10.用NOT EXISTS替代NOT IN
在子查询中,NOT IN子句执行一个内部的排序和合q?br />
无论在哪U情况下QNOT IN都是最低效的,因ؓ它对子查询中的表执行了一个全表遍?br />
Z避免使用NOT INQ我们可以把它改写成外连?Outer Joins)或NOT EXISTS
例如Q?br />
SELECT …
FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO
FROM DEPT
WHERE DEPT_CAT = 'A');
Z提高效率改写?br />
高效
SELECT …
FROM EMP A, DEPT B
WHERE A.DEPT_NO = B.DEPT(+)
AND B.DEPT_NO IS NULL
AND B.DEPT_CAT(+) = 'A'
最高效
SELECT …
FROM EMP E
WHERE NOT EXISTS (SELECT 'X'
FROM DEPT D
WHERE D.DEPT_NO = E.DEPT_NO
AND DEPT_CAT = 'A');
11.用表q接替换EXISTS
通常来说Q采用表q接的方式比EXISTS更有效率
例如Q?br />
SELECT ENAME
FROM EMP E
WHERE EXISTS (SELECT 'X'
FROM DEPT
WHERE DEPT_NO = E.DEPT_NO
AND DEPT_CAT = 'A');
更高?br />
SELECT ENAME
FROM DEPT D, EMP E
WHERE E.DEPT_NO = D.DEPT_NO
AND DEPT_CAT = 'A';
12.用EXISTS替换DISTINCT
当提交一个包含多表信息(比如部门表和雇员表)的查询时Q避免在SELECT子句中用DISTINCTQ一般可以考虑用EXIST替换
例如Q?br />
低效
SELECT DISTINCT DEPT_NO, DEPT_NAME
FROM DEPT D, EMP E
WHERE D.DEPT_NO = E.DEPT_NO
高效
SELECT DEPT_NO, DEPT_NAME
FROM DEPT D
WHERE EXISTS (SELECT 'X'
FROM EMP E
WHERE E.DEPT_NO = D.DEPT_NO);
EXISTS使查询更速,因ؓRDBMS核心模块在子查询的条g一旦满_Q立刻返回结?/p>
13.用烦引提高效?br />
索引是表的一个概念部分,用来提高索数据的效率。实际上QORACLE使用了一个复杂的自^衡B-treel构
通常Q通过索引查询数据比全表扫描要快。当ORACLE扑և执行查询和Update语句的最佌\径时QORACLE优化器将使用索引
同样Q在联结多个表时使用索引也可以提高效率。另一个用烦引的好处是,它提供了主键Qprimary keyQ的唯一性验?/p>
除了那些LONG或LONG RAW数据cdQ你可以索引几乎所有的?br /> 通常在大型表中用烦引特别有效,当然Q在扫描表Ӟ使用索引同样能提高效?/p>
虽然使用索引能得到查询效率的提高Q但是我们也必须注意到它的代?br />
索引需要空间来存储Q也需要定期维护,每当有记录在表中增减或烦引列被修ҎQ烦引本w也会被修改
q意味着每条记录的INSERT、DELETE、UPDATEؓ此多付出4?ơ的盘I/O
因ؓ索引需要额外的存储I间和处理,那些不必要的索引反而会使查询反应时间变?/p>
ORACLE对烦引有两种讉K模式Q?br />
1).索引唯一扫描QINDEX UNIQUE SCANQ?br />
大多数情况下, 优化器通过WHERE子句讉KINDEX
例如Q?br />
表LODGING有两个烦引:建立在LODGING列上的唯一性烦引LODGING_PK和徏立在MANAGER列上的非唯一性烦引LODGING$MANAGER
SELECT *
FROM LODGING
WHERE LODGING = 'ROSE HILL';
在内部,上述SQL被分成两步执行Q?br />
首先QLODGING_PK索引通过索引唯一扫描的方式被讉KQ获得相对应的ROWIDQ然后通过ROWID讉K表的方式执行下一步检?br />
如果被检索返回的列包括在INDEX列中QORACLE不执行W二步的处理Q通过ROWID讉K表)
因ؓ索数据保存在索引中,单单讉K索引可以完全满x询结?/p>
2).索引范围查询(INDEX RANGE SCAN)
适用于两U情?
1>.Z唯一性烦引的一个范围的?br />
2>.Z非唯一性烦引的?br />
?
SELECT LODGING
FROM LODGING
WHERE LODGING LIKE 'M%';
WHERE子句条g包括一pd|ORACLE通过索引范围查询的方式查询LODGING_PK
׃索引范围查询返回一l|它的效率p比烦引唯一扫描低一?/p>
?
SELECT LODGING
FROM LODGING
WHERE MANAGER = 'BILL GATES';
q个SQL的执行分两步QLODGING$MANAGER的烦引范围查询(得到所有符合条件记录的ROWIDQ,通过ROWID讉K表得到LODGING列的?br /> ׃LODGING$MANAGER是一个非唯一性的索引Q数据库不能对它执行索引唯一扫描
WHERE子句中,如果索引列所对应的值的W一个字W由通配W(WILDCARDQ开始,索引不被采?br />
SELECT LODGING
FROM LODGING
WHERE MANAGER LIKE 'QHANMAN';
在这U情况下QORACLE用全表扫?/p>
14.避免在烦引列上用计?br />
WHERE子句中,如果索引列是函数的一部分Q优化器不使用索引而用全表扫?br />
例如Q?br />
低效
SELECT …
FROM DEPT
WHERE SAL * 12 > 25000;
高效
SELECT …
FROM DEPT
WHERE SAL > 25000/12;
请务必注意,索中不要对烦引列q行处理Q如QTRIMQTO_DATEQ类型{换等操作Q破坏烦引,使用全表扫描Q媄响SQL执行效率
15.避免在烦引列上用IS NULL和IS NOT NULL
避免在烦引中使用M可以为空的列QORACLE无法用该索引
对于单列索引Q如果列包含I|索引中将不存在此记录Q?br />
对于复合索引Q如果每个列都ؓI,索引中同样不存在此记录。如果至有一个列不ؓI,则记录存在于索引?/p>
如果唯一性烦引徏立在表的A列和B列上Qƈ且表中存在一条记录的A,Bgؓ(123,null)Q?br />
ORACLE不接受下一条具有相同A,B|123,nullQ的记录插入
如果所有的索引列都为空QORACLE认为整个键gؓI,而空不可能等于空Q因此你可以插入1000条具有相同键值的记录Q当然它们都是空Q?br />
因ؓIg存在于烦引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该烦?/p>
低效Q烦引失效)
SELECT …
FROM DEPARTMENT
WHERE DEPT_CODE IS NOT NULL
16.使用UNION-ALL和UNION
当SQL语句需要UNION两个查询l果集合Ӟq两个结果集合会以UNION-ALL的方式被合ƈQ然后在输出最l结果前q行排序
如果用UNION ALL替代UNIONQ这h序就不是必要了,效率׃因此得到提高
需要注意的是,UNION ALL重复输Z个结果集合中相同记录Q因此还是要从业务需求分析用UNION ALL的可行?/p>
关于索引下列l验请参?
1).如果索数据量过30%的表中记录数Q用烦引将没有显著的效率提?br />
2).在特定情况下Q用烦引也怼比全表扫描慢Q但q是同一个数量上的差距Q而通常情况下,使用索引比全表扫描要快几倍乃臛_千倍!
其他具体内容请参考《ORACLE SQL性能优化pd?/p>
17.使用PrepareStatement
在同一个方法中Q当循环使用SQL文时Qؓ了提高性能Q?br />
请用PreparedStatement。注意,
仅限使用于少数的模块?br />
Ҏ如下Q?/p>
? PreparedStatement stmt
= conn.prepareStatement("select a from TABLE_A where b=? c=?");
for(?? ){
???? stmt.setInt(1, varB);
???? stmt.setString(2, varC);
? ResultSet rst = stmt.executeQuery();
}
如何选择
Web
开发框?/span>
开发框架的选择Q始l是个仁者见仁、智者见智的事情。尤其是
Web
层的开发框Ӟ数量非常多,而且各有特色Q如Q?/span>
Struts
?/span>
WebWork
?/span>
Spring MVC
?/span>
Tapestry
?/span>
JSF
?/span>
WebPage3.0…?/span>
{等?/span>
下面先来看看Z么要使用
Web
开发框?/span>
一Q用框架的必然?/span>
框架Q即
framework
。其实就是某U应用的半成品,把不同应用程序中有共性的一些东西抽取出来,做成一个半成品E序Q这L半成品就是所谓的E序框架?/span>
软gpȝ发展C天已l很复杂了,特别是服务器端YӞ涉及到的知识Q内容,问题太多。在某些斚w使用别h成熟的框Ӟq当于让别人帮你完成一些基工作Q你只需要集中精力完成系l的业务逻辑设计。这hơ开发就不用白手起家Q而是可以在这个基上开始搭建?/span>
使用框架的最大好处:减少重复开发工作量、羃短开发时间、降低开发成本。同时还有其它的好处Q如QɽE序设计更合理、程序运行更E_{。基于这些原因,基本上现在在开发中Q都会选用某些合适的开发框Ӟ来帮助快速高效的开发应用系l?/span>
了解了用框架的必然性,下面来看看如何选择Q当然我们的话题集中?/span>
Web
层的开发框架。在谈这个问题之前,先来看看我们?/span>
Web
开发中I竟需要做些什么工作:
二:
Web
层开发的工作
?/span>
J2EE
开发中Q分层是基本的思想Q?/span>
3
层架构或者多层架构早已深入h心,在这里我们就把目光集中到
Web
层,看看到底
Web
层开发做了那些工作:
1
Q数据展C?/span>
Web
层需要从逻辑层获取需要展C的数据Q然后以合理的方式在面q行展示
2
QhZ?/span>
用户需要从界面上输入数据,在界面上q行按钮点击Q进而触发事Ӟ标准的事仉动模型,然后跟后台进行数据交换,出现新的界面?/span>
3
Q收集数据,调用逻辑层接?/span>
Web
层收到用L事ghQ需要调用相应的逻辑层接口来q行处理Q?/span>
Web
层是不会有Q何逻辑处理的。调用逻辑层接口,需要传递参敎ͼq时需要收集用户在界面上输入的数据Q然后进行组l,l织成ؓ逻辑层接口需要的数据装形式Q通常都是
ValueObject
Q?/span>
4
Q根据逻辑层的数据来重新展C页?/span>
逻辑层处理完了,需要返回数据或信息到界面上。这个时?/span>
Web
层需要根据返回的值选择合适的面Q然后展C些数据或者信息?/span>
从上面可以看出,
Web
层开发的主要工作集中在展CZQ也是囑Ş用户界面。这一部分是用L观感受应用程序的H口Q也是用戯求最多的地方Q其表现形式也是最丰富的?/span>
三:
Web
层开发的步骤
下面再来ȝ一?/span>
Web
层开发的大致步骤Q也是需要开发h员做的工作)Q?/span>
注意Q这里讨论的
Web
层开发,是不使用M开发框架时候的开发?/span>
1
Q写面
Html
Q到底有哪些数据需要在界面上表?/span>
2
Q每个数据的具体表现形式Q如Q有的需要表现成Z拉列表,有的需要表现成为单选按钮等?/span>
3
Q界面表现Ş式的逻辑布局Q所谓逻辑布局是指某些数据的表现Ş式应该放在前面,某些应该攑֜后面Q某些放在上面,某些攑֜下面。如Q某个请假申L业务Q有请假开始时间和l束旉Q很明显开始时间的表现应该排在结束时间的前面。而美工是负责最后页面的观Q一般美工不能动界面的逻辑布局?/span>
4
Q完成前?/span>
3
步,面的表现Ş式的大致模样有了,下面需要来做功能性的开发。第一个就是这些表现Ş式的值的来源Q如Q下拉列表显C的g什么地Ҏ。值的来源方式很多Q有数据库中来、固定倹{某断程序运行的中间l果、前面页面传递过来等{,当然典型的还是来自数据库?/span>
好了Q确定了值的来源Q开发h员就要写代码来获取这些|然后把这些D值到对应的表现Ş式里面?/span>
5
Q还有一些比较特D,也就是真实操作的是一cd|但是在界面上昄的是另一cd|比如Q数据库中有用户~号Q到了界面上得昄用户姓名Q但是所有的操作都是要操作用LL。我们把q种情况分做Q真实值和表现|他们有一定的内在联系。这些都是要开发h员去转化和维护的?/span>
6
Q接下来应该开发功能性的事g响应了。用LM某个按钮或者触发了某个事gQ首先是客户端:数据、客L事g处理Q然后提交到服务端,服务端要获取到客L提交的数据,然后调用相应的逻辑层接口来响应。当然如何写逻辑层的实现q里׃去谈Z?/span>
7
Q逻辑层执行完q后Q返回数据和信息?/span>
Web
层,开发h员还需要写代码d理,选择哪个面来显C,如何昄q些数据和信息等?/span>
8
Q在整个交互的过E中Q还必须考虑到如何控制权限,如:某些数据不能昄Q某些数据不能编辑等{;同样q需要考虑到消息的配置和国际化{等。这些功能v源于逻辑层,但是实际的控制要?/span>
Web
层,q些都需要开发h员来控制?/span>
9
Q完成了上面的开发步骤,面基本的功能开发就告一D落Q接下来开发h员需要考虑面观的问题了。大家可能会_
?/span>
不是有美工吗Q还需要开发h员干什么?
?/span>
。事实上工多半只能Z个静态页面的化模版Q美工对于一?/span>
Java
代码?/span>
Html
的杂物Q多半是没有办法的,更不要说q有一些内Ҏ动态生成的Q美工就更不可能搞定了。还是得开发h员上阵,按照工l的模版Q开始添?/span>
Css
Q?/span>
class
?/span>
id
?/span>
style…?
10
Q完成上面的开发,基本面的开发工作就完成了,最后的一个步骤就是把各个面有机的组lv来,开发应用程序的整体应用D框架Q通常是菜单Q然后把各个功能面跟菜单结合v来,形成一个完整的应用?/span>
在这里我们省略了开发期反复的调试过E,仅ȝ开发的步骤?/span>
四:选择
Web
开发框架的目的
了解了如果没有框Ӟ我们需要做的工作,q对选择框架有非常大的帮助?/span>
框架Q直白点_是一个半成品Q能够帮我们做一些事情的半成品?/span>
框架的选择Q就是看哪个框架最合适,从而减开发的工作量,提高开发的效率和质量,q有效减维护的工作量,最l达到节U综合开发成本,获取更多的收益?/span>
五:选择
Web
开发框架的标准
声明Q这里所谈的选择
Web
开发框架的标准Q只是我们的ȝ和一家之aQƈ不是放之四v而皆准的真理Q请Ҏ您的体会客观的看待我们的ȝ?/span>
另外Q我们这里更多的讨论业务功能性应用程序的
Web
开发框架?/span>
1
Q选择能够Ҏ们的开发过E提供更多、更好帮助的
Web
开发框?/span>
2
Q?/span>
Web
开发框架的学习一定要单,上手一定要快,没有什么比使用能得到更q体会。那些动不动需要半个月或者一个月学习周期的框Ӟ实在是有些恐怖?/span>
3
Q一定要能得到很好的技术支持,在应用的q程中,或多或少都会出现q样或者那L问题Q如果不能很快很好的解决Q会Ҏ个项目开发带来媄响。一定要考虑l合成本Q其实这是目前应用开源Y件最大的问题Q碰到问题除了死肯文档就是查阅源代码Q或者是|上搜寻解决的办法,通常一个问题就会导?/span>
1-2
天的开发停,严重的甚至需要一个星期或者更长,一个项目有上这么几ơ,目整体的开发成本嗖嗖的׃M?/span>
4
Q?/span>
Web
开发框架结合其他技术的能力一定要强,比如Q在逻辑层要使用
Spring
或?/span>
Ejb3
Q那?/span>
Web
开发框架一定要能很ҎQ很方便的与它们q行l合?/span>
5
Q?/span>
Web
开发框架的扩展能力一定要强。在好的框架都有力所不及的地方,q就要求能很Ҏ的扩?/span>
Web
开发框架的功能Q以满新的业务需要。同时要注意扩展的简单性,如果扩展框架的功能代价非常大Q还不如不用呢?/span>
6
Q?/span>
Web
开发框架最好能提供可视化的开发和配置Q可视化开发对开发效率的提高Q已l得C界公认?/span>
7
Q?/span>
Web
开发框架的设计l构一定要合理Q应用程序会Zq个框架Q框架设计的不合理会大大影响到整个应用的可扩展性?/span>
8
Q?/span>
Web
开发框架一定要是运行稳定的Q运行效率高的。框架的E_性和q行效率直接影响到整个系l的E_性和效率?/span>
9
Q?/span>
Web
开发框架一定要能很好的l合目前公司的积累。在多年的开发中已有了很多积累,不能因ؓ使用
Web
开发框架就不能再用了Q那未免有些得不偿失?/span>
10
Q选择开发框架另外要注意的一点就是:M开发框枉不可能是十全十美的,也不可能是适应所有的应用场景的,也就是说M开发框枉有它适用的范围。所以选择的时候要注意判断应用的场景和开发框架的适用性?/span>
发框架的功能Q以满新的业务需要。同时要注意扩展的简单性,如果扩展框架的功能代价非常大Q还不如不用呢?/span>
Struts
应用
~者按Q当作?span lang="EN-US"> Chuck CavanessQ著有?span lang="EN-US">Programming Jakarta Struts》一书)所在的|络公司军_采用Struts框架之后Q?span lang="EN-US">Chuck曄p了好几个月来研究如何用它来构建公司的应用pȝ。本文叙q的正是作者在q用Strutsq程中来之不易的若干l验和心得。如果你是个负责通过jsp?span lang="EN-US">servlet开?span lang="EN-US">Web应用?span lang="EN-US">JavaE序员,q且也正在考虑采用ZStruts的构建方法的话,那么你会在这里发现很多颇有见地同时也很有价值的信息?span lang="EN-US">
1. 只在必要的时候才考虑扩展Struts框架
一个好?span lang="EN-US">framework有很多优点,首先Q它必须能够满用户的可预见的需求。ؓ?span lang="EN-US"> Struts?span lang="EN-US">Web 应用提供了一个通用的架构,q样开发h员可以把_֊集中在如何解军_际业务问题上。其ơ,一个好?span lang="EN-US">frameworkq必能够在适当的地Ҏ供扩展接口,以便应用E序能扩展该框架来更好的适应使用者的实际需要?span lang="EN-US">
如果Struts framework在Q何场合,M目中都能很好的满需求,那真是太了。但是实际上Q没有一个框架声U能做到q一炏V一定会有一些特定的应用需求是框架的开发者们无法预见到的。因此,最好的办法是提供_的扩展接口,使得开发工E师能够调整struts来更好的W合他们的特D要求?span lang="EN-US">
?span lang="EN-US">Struts framework中有很多地方可供扩展和定制。几乎所有的配置c都能被替换为某个用户定制的版本Q这只要单的修改一?span lang="EN-US">Struts的配|文件就可以做到?span lang="EN-US">
其他lg?span lang="EN-US">ActionServlet?span lang="EN-US"> RequestProcessor 也能用自定义的版本代?span lang="EN-US">. 甚至q?span lang="EN-US">Struts 1.1里才有的新特性也是按照扩展的原则来设计的。例如,在异常处理机制中允许用户定制异常处理的句柄Q以便更好的对应用系l发生的错误做出响应?span lang="EN-US">
作ؓ框架的这U可调整Ҏ在它更适合你的应用的同时也在很大的E度上媄响了目开发的效果。首先,׃您的应用是基于一个现有的成熟的、稳定的framework?span lang="EN-US">StrutsQ测试过E中发现的错误数量将会大大减,同时也能~短开发时间和减少资源的投入。因Z不再需要投入开发力量用于编写基框架的代码了?span lang="EN-US">
然?span lang="EN-US">, 实现更多的功能是要花Ҏ大的代h的。我们必d心避免不必要的滥用扩展性能Q?span lang="EN-US"> Struts是由核心包加上很多工具包构成的,它们已经提供了很多已l实现的功能。因此不要盲目的扩展Struts框架Q要先确定能不能采用其他Ҏ使用现有的功能来实现?在决定编写扩展代码前务必要确?span lang="EN-US">Struts的确没有实现你要的功能。否则重复的功能会导致乱将来还得花贚w外的_֊清除它?span lang="EN-US">
2. 使用异常处理声明
要定义应用程序的逻辑程Q成熟的l验是推荐在代码之外Q用配置的方法来实现Q而不是写dE序代码中的。在J2EE中,q样的例子比比皆是。从实现EJB的安全性和事务性行为到描述JMS消息和目的地之间的关p,很多q行时的处理程都是可以在程序之外定义的?span lang="EN-US">
Struts 创徏者从一开始就采用q种ҎQ通过配置Struts的配|文件来定制应用pȝq行时的各个斚w。这一点在版本1.1的新Ҏ上得到延箋Q包括新的异常处理功能。在Struts framework以前的版本中Q开发h员不得不自己处理Struts应用中发生的错误情况。在最新的版本中,情况大大的改观了Q?span lang="EN-US">Struts Framework提供了内|的一个称?span lang="EN-US"> ExceptionHandler 的类Q?用于pȝ~省处理actionc运行中产生的错误。这也是在上一个技巧中我们提到?span lang="EN-US">framework许多可扩展接口之一?span lang="EN-US">
Struts~省?span lang="EN-US"> ExceptionHandlercM生成一?span lang="EN-US">ActionError对象q保存在适当的范_scopeQ对象中。这样就允许JSP面使用错误cL提醒用户出现什么问题。如果你认ؓq不能满你的需求,那么可以很方便的实现你自qExcepionHandlercR?span lang="EN-US">
具体定制异常处理的方法和机制
要定制自q异常处理机制Q第一步是l承org.apache.struts.action.ExceptionHandlercR这个类?span lang="EN-US">2个方法可以覆盖,一个是excute()另外一个是storeException(). 在多数情况下Q只需要覆盖其中的excute()Ҏ。下面是ExceptionHandlercȝexcute()Ҏ声明Q?span lang="EN-US">
正如你看到的Q该Ҏ有好几个参数Q其中包括原始的异常。方法返回一?span lang="EN-US">ActionForward对象Q用于异常处理结束后?span lang="EN-US">controllercd到请求必{发的地方厅R?span lang="EN-US">
当然您可以实CQ何处理,但一般而言Q我们必L查抛出的异常,q对该cd的异常进行特定的处理。缺省的Q系l的异常处理功能是创Z个出错信息,同时把请求{发到配置文g中指定的地方厅R?定制异常处理的一个常见的例子是处理嵌套异常。假设该异常包含有嵌套异常,q些嵌套异常又包含了其他异常Q因此我们必覆盖原来的execute()ҎQ对每个异常~写出错信息?span lang="EN-US">
一旦你创徏了自qExceptionHandler c,应该在Struts配置文g中的部分声明q个c,以便?span lang="EN-US">Struts知道改用你自定义的异常处理取代缺省的异常处理.
可以配置你自qExceptionHandler cL用于Action Mapping特定的部分还是所有的Action对象。如果是用于Action Mapping特定的部分就?元素中配|。如果想让这个类可用于所有的Action对象,可以?元素中指定。例如,假设我们创徏了异常处理类CustomizedExceptionHandler用于所有的Actionc?span lang="EN-US">, 元素定义如下所C:
?元素中可以对很多属性进行设|。在本文中,最重要的属性莫q于handler属?span lang="EN-US">, handler属性的值就是自定义的承了ExceptionHandlercȝ子类的全名?假如该属性没有定义,Struts会采用自q~省倹{当Ӟ其他的属性也很重要,但如果想覆盖~省的异常处理的话,handler无疑是最重要的属性?span lang="EN-US">
最后必L出的一ҎQ你可以有不同的异常处理cL处理不同的异常。在上面的例子中Q?span lang="EN-US">CustomizedExceptionHandler用来处理Mjava.lang.Exception的子c?span lang="EN-US">. 其实Q你也可以定义多个异常处理类Q每一个专门处理不同的异常树。下面的XML片断解释了如何配|以实现q一炏V?span lang="EN-US">
在这里,一旦有异常抛出Q?span lang="EN-US">struts framework试囑֜配置文g中找?span lang="EN-US">ExceptionHandlerQ如果没有找刎ͼ那么struts沿着该异常的父类链一层层往上找直到发现匚w的ؓ止。因此,我们可以定义一个层ơ型的异常处理关pȝ构,在配|文件中已经体现了这一炏V?span lang="EN-US">
3. 使用应用模块Q?span lang="EN-US">Application ModulesQ?span lang="EN-US">
Struts 1.1的一个新Ҏ是应用模块的概c应用模块允许将单个Struts应用划分成几个模块,每个模块有自qStruts配置文gQ?span lang="EN-US">JSP面Q?span lang="EN-US">Action{等。这个新Ҏ是Z解决大中型的开发队伍抱怨最多的一个问题,即ؓ了更好的支持q行开发允许多个配|文件而不是单个配|文件?span lang="EN-US">
注:在早期的beta版本中,该特性被UCؓ子应用(sub-applicationsQ,最q的改名目的是ؓ了更多地反映它们在逻辑上的分工?span lang="EN-US">
昄Q当很多开发h员一起参加一个项目时Q单个的Struts配置文g很容易引赯源冲H。应用模块允?span lang="EN-US">Struts按照功能要求q行划分Q许多情况已l证明这h贴近实际。例如,假设我们要开发一个典型的商店应用E序。可以将l成部分划分成模块比?span lang="EN-US">catalogQ商品目录), customerQ顾客), customer serviceQ顾客服务), orderQ订单){。每个模块可以分布到不同的目录下Q这样各部分的资源很Ҏ定位Q有助于开发和部v。图1 昄了该应用的目录结构?span lang="EN-US">
?span lang="EN-US"> 1. 一个典型的商店应用E序的目录结?span lang="EN-US">
注:如果你无需项目划分成多个模块Q?span lang="EN-US">Struts框架支持一个缺省的应用模块。这׃得应用程序也可以?span lang="EN-US">1.0版本下创建,h可移植性,因ؓ应用E序会自动作为缺省的应用模块?span lang="EN-US">
Z使用多应用模块功能,必须执行以下几个准备步骤Q?span lang="EN-US">
?为每个应用模块创建独立的Struts配置文g?span lang="EN-US">
?配置Web 部v描述W?span lang="EN-US"> Web.xml文g?span lang="EN-US">
?使用org.apache.struts.actions.SwitchAction 来实现程序在模块之间的蟩?span lang="EN-US">.
创徏独立?span lang="EN-US">Struts配置文g
每个Struts应用模块必须拥有自己的配|文件。允许创q独立于其他模块的ActionQ?span lang="EN-US">ActionFormQ异常处理甚x多?span lang="EN-US">
l箋以上面的商店应用E序ZQ我们可以创Z下的配置文gQ一个文件名?span lang="EN-US">struts-config-catalog.xmlQ包?span lang="EN-US">catalogQ商品目录)?span lang="EN-US">items(商品清单)、和其它与库存相关的功能的配|信息;另一个文件名?span lang="EN-US">struts- config-order.xml, 包含?span lang="EN-US">orderQ订单)?span lang="EN-US">order trackingQ订单跟t)的设|。第三个配置文g?span lang="EN-US">struts-config.xml,其中含有属于~省的应用模块中的一般性的功能?span lang="EN-US">
配置Web部v描述W?span lang="EN-US">
?span lang="EN-US">Struts的早期版本中Q我们在Web.xml中指?span lang="EN-US">Struts配置文g的\径。好在这Ҏ变,有助于向后兼宏V但对于多个应用模块Q我们需要在Web部v描述W中增加新的配置文g的设定?span lang="EN-US">
对于~省的应用(包括Struts的早期版本)Q?span lang="EN-US">Struts framework ?span lang="EN-US">Web.xml文g中查扑ָ?span lang="EN-US">config的元?Q用于蝲?span lang="EN-US">Action mapping 和其它的应用E序讑֮。作Z子,以下?span lang="EN-US">XML片断展现一个典型的 元素Q?span lang="EN-US">
注:如果在现有的 元素中找不到"config"关键字,Struts framework缺省地使用/WEB/struts-config.xml
Z支持多个应用模块(Struts 1.1的新Ҏ?span lang="EN-US">)Q必d加附加的 元素。与~省?元素不同的是Q附加的 元素与每个应用模块对应,必须?span lang="EN-US">config/xxx的Ş式命名,其中字符?span lang="EN-US">xxx代表该模块唯一的名字。例如,在商店应用程序的例子中, 元素可定义如下(注意_体字部分)Q?span lang="EN-US">
W一?元素对应~省的应用模块。第二和W三个元素分别代表非~省应用模块catalog ?span lang="EN-US"> order?span lang="EN-US">
?span lang="EN-US">Struts载入应用E序Ӟ它首先蝲入缺省应用模块的配置文g。然后查扑ָ有字W串config/xxx 形式的附加的初始化参数。对每个附加的配|文件也q行解析q蝲入内存。这一步完成后Q用户就可以很随意地?span lang="EN-US">config/后面的字W串也就是名字来调用相应的应用模块?span lang="EN-US">
多个应用模块之间调用Actionc?span lang="EN-US">
在ؓ每个应用模块创徏独立的配|文件之后,我们有可能需要调用不同的模块?span lang="EN-US">Action。ؓ此必M?span lang="EN-US">Struts框架提供?span lang="EN-US">SwitchActioncR?span lang="EN-US">Struts 会自动将应用模块的名字添加到URL,如Struts 自动d应用E序的名字加?span lang="EN-US">URL一栗应用模块是Ҏ架的一个新的扩充,有助于进行ƈ行的团队开发。如果你的团队很那没必要用到q个Ҏ,不必q行模块化。当Ӟq是只有一个模块,pȝq是一Lq作?span lang="EN-US">
4. ?span lang="EN-US">JSP攑ֈWEB-INF后以保护JSP源代?span lang="EN-US">
Z更好C护你?span lang="EN-US">JSP避免未经授权的访问和H视Q?一个好办法是将面文g存放?span lang="EN-US">Web应用?span lang="EN-US">WEB-INF目录下?span lang="EN-US">
通常JSP开发h员会把他们的面文g存放?span lang="EN-US">Web应用相应的子目录下。一个典型的商店应用E序的目录结构如?span lang="EN-US">2所C。跟catalog Q商品目录)相关?span lang="EN-US">JSP被保存在catalog子目录下。跟customer相关?span lang="EN-US">JSPQ跟订单相关?span lang="EN-US">JSP{都按照q种Ҏ存放?span lang="EN-US">
?span lang="EN-US"> 2.Z不同的功?span lang="EN-US"> JSP 被放|在不同的目录下
q种Ҏ的问题是q些面文gҎ被偷看到源代码,或被直接调用。某些场合下q可能不是个大问题,可是在特定情形中却可能构成安全隐患。用户可以绕q?span lang="EN-US">Struts?span lang="EN-US">controller直接调用JSP同样也是个问题?span lang="EN-US">
Z减少风险Q可以把q些面文gUdWEB-INF 目录下。基?span lang="EN-US">Servlet的声明,WEB-INF不作?span lang="EN-US">Web应用的公共文档树的一部分。因此,WEB-INF 目录下的资源不是为客L接服务的。我们仍然可以?span lang="EN-US">WEB-INF目录下的JSP面来提供视囄客户Q客户却不能直接h讉KJSP?span lang="EN-US">
采用前面的例子,?span lang="EN-US">3昄?span lang="EN-US">JSP面UdWEB-INF 目录下后的目录结?span lang="EN-US">
?span lang="EN-US"> 3. JSP存放?span lang="EN-US"> WEB-INF 目录下更为安?span lang="EN-US">
如果把这?span lang="EN-US">JSP面文gUdWEB-INF 目录下,在调用页面的时候就必须?span lang="EN-US">"WEB-INF"d?span lang="EN-US">URL中。例如,在一?span lang="EN-US">Struts配置文g中ؓ一?span lang="EN-US">logoff action写一?span lang="EN-US">Action mapping。其?span lang="EN-US">JSP的\径必M"WEB-INF"开头。如下所C:h意粗体部?span lang="EN-US">.
q个Ҏ在Q何情况下都不׃ؓStruts实践中的一个好Ҏ。是唯一要注意的技巧是你必LJSP和一?span lang="EN-US">Struts action联系h。即使该Action只是一个很基本的很?span lang="EN-US">JSPQ也L要调用一?span lang="EN-US">ActionQ再由它调用JSP?span lang="EN-US">
最后要说明的是Qƈ不是所有的容器都能支持q个Ҏ?span lang="EN-US">WebLogic早期的版本不能解?span lang="EN-US">Servlet声明Q因此无法提供支持,据报道在新版本中已经改进了。M使用之前先检查一下你?span lang="EN-US">Servlet容器?span lang="EN-US">
5. 使用 Prebuilt ActioncL升开发效?span lang="EN-US">
Struts framework带有好几?span lang="EN-US">prebuilt Actionc,使用它们可以大大节省开发时间。其中最有用的是org.apache.struts.actions.ForwardAction ?span lang="EN-US"> org.apache.struts.actions.DispatchAction.
使用 ForwardAction
在应用程序中Q可能会l常出现只要?span lang="EN-US">Action对象转发到某?span lang="EN-US">JSP的情c在上一点中曾提到L?span lang="EN-US">Action调用JSP是个好习惯。如果我们不必在Action中执行Q何业务逻辑Q却又想遵@?span lang="EN-US">Action讉K面的话Q就可以使用ForwardActionQ它可以使你免去创徏许多I的ActioncR运?span lang="EN-US">ForwardAction的好处是不必创徏自己?span lang="EN-US">Actionc,你需要做的仅仅是?span lang="EN-US">Struts配置文g中配|一?span lang="EN-US">Action mapping?span lang="EN-US">
举个例子Q假定你有一?span lang="EN-US">JSP文gindex.jsp Q而且不能直接调用该页面,必须让程序通过一?span lang="EN-US">Actionc调用,那么Q你可以建立以下?span lang="EN-US">Action mapping来实现这一点:
正如你看到的Q当 /home 被调用时, ׃调用ForwardAction q把h转发?span lang="EN-US"> index.jsp 面.
再讨Z下不通过一?span lang="EN-US">Actioncȝ接{发到某个面的情况,必须注意我们仍然使用 元素中的forward属性来实现转发的目标。这?元素定义如下Q?span lang="EN-US">
以上两种Ҏ都可以节省你的时_q有助于减少一个应用所需的文件数?span lang="EN-US">
使用 DispatchAction
DispatchAction?span lang="EN-US">Struts包含的另一个能大量节省开发时间的ActioncR与其它ActioncM提供单个execute()Ҏ实现单个业务不同Q?span lang="EN-US">DispatchAction允许你在单个ActioncM~写多个与业务相关的Ҏ。这样可以减?span lang="EN-US">Actioncȝ数量Qƈ且把相关的业务方法集合在一起得维护v来更Ҏ?span lang="EN-US">
要?span lang="EN-US">DispatchAction的功能,需要自己创Z个类Q通过l承抽象?span lang="EN-US">DispatchAction得到。对每个要提供的业务Ҏ必须有特定的Ҏsignature。例如,我们惌提供一个方法来实现对购物Rd商品清单Q创Z一个类ShoppingCartDispatchAction提供以下的方法:
那么Q这个类很可能还需要一?span lang="EN-US">deleteItem()Ҏ从客L购物车中删除商品清单Q还?span lang="EN-US">clearCart()Ҏ清除购物车等{。这时我们就可以把这些方法集合在单个Actionc,不用为每个方法都提供一?span lang="EN-US">ActioncR?span lang="EN-US">
在调?span lang="EN-US">ShoppingCartDispatchAction里的某个ҎӞ只需?span lang="EN-US">URL中提供方法名作ؓ参数倹{就是说Q调?span lang="EN-US">addItem()Ҏ?URL看v来可能类gQ?span lang="EN-US">
http://myhost/storefront/action/cart?method=addItem
其中method参数指定ShoppingCartDispatchAction中要调用的方法。参数的名称可以L配置Q这里用的"method"只是一个例子。参数的名称可以?span lang="EN-US">Struts配置文g中自行设定?span lang="EN-US">
6.使用动?span lang="EN-US">ActionForm
?span lang="EN-US">Struts framework中,ActionForm对象用来包装HTML表格数据Q包括请求)Qƈq回q回动态显C给用户的数据。它们必L完全?span lang="EN-US">JavaBeanQƈl承.Struts 里面?span lang="EN-US">ActionFormc,同时Q用户可以有选择地覆盖两个缺省方法?span lang="EN-US">
该特性能节省很多旉Q因为它可以协助q行自动的表现层的验证?span lang="EN-US">ActionForm的唯一~点是必Mؓ不同?span lang="EN-US">HTML表格生成多个ActionForm cM保存数据。例如,如果有一个页面含有用L注册信息Q另一个页面则含有用户的介lh的信息,那么需要有两个不同?span lang="EN-US">ActionFormcR这在大的应用系l中׃Dq多?span lang="EN-US">ActionFormcR?span lang="EN-US">Struts 1.1Ҏ做出了很好的改进Q引入了动?span lang="EN-US">ActionFormcL?span lang="EN-US">
通过Struts framework中的DynaActionFormcd其子cd以实现动态的ActionForm Q动态的ActionForm允许你通过Struts的配|文件完?span lang="EN-US">ActionForm的全部配|;再也没有必要在应用程序中创徏具体?span lang="EN-US">ActionFormcR具体配|方法是Q在Struts的配|文仉过增加一?元素Q将type属性设定成DynaActionForm或它的某个子cȝ全名。下面的例子创徏了一个动态的ActionForm名ؓlogonFormQ它包含两个实例变量Q?span lang="EN-US">username ?span lang="EN-US"> password.
动态的ActionForm可以用于ActioncdJSPQ用方法跟普通的ActionForm相同Q只有一个小差别。如果用普通的ActionForm对象则需要提?span lang="EN-US">get ?span lang="EN-US"> setҎ取得和设|数据。以上面的例子而言Q我们需要提?span lang="EN-US">getUsername() ?span lang="EN-US"> setUsername()Ҏ取得和设|?span lang="EN-US">username变量Q同样地有一Ҏ法用于取得和讄password变量.
q里我们使用的是DynaActionFormQ它变量保存在一?span lang="EN-US">Mapcd象中Q所以必M?span lang="EN-US">DynaActionForm cM?span lang="EN-US">get(name) ?span lang="EN-US"> set(name)ҎQ其中参?span lang="EN-US">name是要讉K的实例变量名。例如要讉KDynaActionForm?span lang="EN-US">username的|可以采用cM的代码:
String username = (String)form.get("username");
׃值存攑֜一?span lang="EN-US">Map对象Q所以要记得?span lang="EN-US">get()Ҏq回?span lang="EN-US">Object对象做强制性类型{换?span lang="EN-US">
DynaActionForm有好几个很有用的子类。其中最重要的是DynaValidatorForm Q这个动态的ActionForm?span lang="EN-US">Validator 一起利用公qValidator包来提供自动验证。这个特性你得以在E序代码之外指定验证规则。将两个Ҏ结合用对开发h员来说将非常有吸引力?span lang="EN-US">
7. 使用可视化工?span lang="EN-US">
自从Struts 1.0 分布以来Q就出现了不可视化工具用于协助创徏Q修改和l护Struts的配|文件。配|文件本w是ZXML格式Q在大中型的开发应用中会增大变得很W拙。ؓ了更方便的管理这些文Ӟ一旦文件大C无法一目了然的时候,试着采用其中的一U?span lang="EN-US">GUI 工具协助开发。商业性的和开放源代码的工具都有不,?span lang="EN-US">1列出了可用的工具和其相关链接Q从那里可以获取更多信息?span lang="EN-US">
?span lang="EN-US"> 1. Struts GUI 工具
应用E序 性质 |址
Adalon 商业软g http://www.synthis.com/products/adalon
Easy Struts 开放源?span lang="EN-US"> http://easystruts.sourceforge.net/
Struts Console 免费 http://www.jamesholmes.com/struts/console
JForms 商业软g http://www.solanasoft.com/
Camino 商业软g http://www.scioworks.com/scioworks_camino.html
Struts Builder 开放源?span lang="EN-US"> http://sourceforge.net/projects/rivernorth/
StrutsGUI 免费 http://www.alien-factory.co.uk/struts/struts-index.html