2007年09月06日

哈哈,好久没来了, 这是我新的blog 地址:

http://www.lifetags.net/log/

欢迎访问!

2005年03月05日

Five score years ago, a great American, in whose symbolic shadow we stand signed the Emancipation Proclamation. This momentous decree came as a great beacon light of hope to millions of Negro slaves who had been seared in the flames of withering injustice. It came as a joyous daybreak to end the long night of captivity.

But one hundred years later, we must face the tragic fact that the Negro is still not free. One hundred years later, the life of the Negro is still sadly crippled by the manacles of segregation and the chains of discrimination. One hundred years later, the Negro lives on a lonely island of poverty in the midst of a vast ocean of material prosperity. One hundred years later, the Negro is still languishing in the corners of American society and finds himself an exile in his own land. So we have come here today to dramatize an appalling condition.

In a sense we have come to our nation’s capital to cash a check. When the architects of our republic wrote the magnificent words of the Constitution and the declaration of Independence, they were signing a promissory note to which every American was to fall heir. This note was a promise that all men would be guarranteed the inalienable rights of life, liberty, and the pursuit of happiness.

It is obvious today that America has defaulted on this promissory note insofar as her citizens of color are concerned. Instead of honoring this sacred obligation, America has given the Negro people a bad check which has come back marked "insufficient funds." But we refuse to believe that the bank of justice is bankrupt. We refuse to believe that there are insufficient funds in the great vaults of opportunity of this nation. So we have come to cash this check — a check that will give us upon demand the riches of freedom and the security of justice. We have also come to this hallowed spot to remind America of the fierce urgency of now. This is no time to engage in the luxury of cooling off or to take the tranquilizing drug of gradualism. Now is the time to rise from the dark and desolate valley of segregation to the sunlit path of racial justice. Now is the time to open the doors of opportunity to all of God’s children. Now is the time to lift our nation from the quicksands of racial injustice to the solid rock of brotherhood.

It would be fatal for the nation to overlook the urgency of the moment and to underestimate the determination of the Negro. This sweltering summer of the Negro’s legitimate discontent will not pass until there is an invigorating autumn of freedom and equality. Nineteen sixty-three is not an end, but a beginning. Those who hope that the Negro needed to blow off steam and will now be content will have a rude awakening if the nation returns to business as usual. There will be neither rest nor tranquility in America until the Negro is granted his citizenship rights. The whirlwinds of revolt will continue to shake the foundations of our nation until the bright day of justice emerges.

But there is something that I must say to my people who stand on the warm threshold which leads into the palace of justice. In the process of gaining our rightful place we must not be guilty of wrongful deeds. Let us not seek to satisfy our thirst for freedom by drinking from the cup of bitterness and hatred.

We must forever conduct our struggle on the high plane of dignity and discipline. We must not allow our creative protest to degenerate into physical violence. Again and again we must rise to the majestic heights of meeting physical force with soul force. The marvelous new militancy which has engulfed the Negro community must not lead us to distrust of all white people, for many of our white brothers, as evidenced by their presence here today, have come to realize that their destiny is tied up with our destiny and their freedom is inextricably bound to our freedom. We cannot walk alone.

And as we walk, we must make the pledge that we shall march ahead. We cannot turn back. There are those who are asking the devotees of civil rights, "When will you be satisfied?" We can never be satisfied as long as our bodies, heavy with the fatigue of travel, cannot gain lodging in the motels of the highways and the hotels of the cities. We cannot be satisfied as long as the Negro’s basic mobility is from a smaller ghetto to a larger one. We can never be satisfied as long as a Negro in Mississippi cannot vote and a Negro in New York believes he has nothing for which to vote. No, no, we are not satisfied, and we will not be satisfied until justice rolls down like waters and righteousness like a mighty stream.

I am not unmindful that some of you have come here out of great trials and tribulations. Some of you have come fresh from narrow cells. Some of you have come from areas where your quest for freedom left you battered by the storms of persecution and staggered by the winds of police brutality. You have been the veterans of creative suffering. Continue to work with the faith that unearned suffering is redemptive.

Go back to Mississippi, go back to Alabama, go back to Georgia, go back to Louisiana, go back to the slums and ghettos of our northern cities, knowing that somehow this situation can and will be changed. Let us not wallow in the valley of despair.

I say to you today, my friends, that in spite of the difficulties and frustrations of the moment, I still have a dream. It is a dream deeply rooted in the American dream.

I have a dream that one day this nation will rise up and live out the true meaning of its creed: "We hold these truths to be self-evident: that all men are created equal."

I have a dream that one day on the red hills of Georgia the sons of former slaves and the sons of former slaveowners will be able to sit down together at a table of brotherhood.

I have a dream that one day even the state of Mississippi, a desert state, sweltering with the heat of injustice and oppression, will be transformed into an oasis of freedom and justice.

I have a dream that my four children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character.

I have a dream today.

I have a dream that one day the state of Alabama, whose governor’s lips are presently dripping with the words of interposition and nullification, will be transformed into a situation where little black boys and black girls will be able to join hands with little white boys and white girls and walk together as sisters and brothers.

I have a dream today.

I have a dream that one day every valley shall be exalted, every hill and mountain shall be made low, the rough places will be made plain, and the crooked places will be made straight, and the glory of the Lord shall be revealed, and all flesh shall see it together.

This is our hope. This is the faith with which I return to the South. With this faith we will be able to hew out of the mountain of despair a stone of hope. With this faith we will be able to transform the jangling discords of our nation into a beautiful symphony of brotherhood. With this faith we will be able to work together, to pray together, to struggle together, to go to jail together, to stand up for freedom together, knowing that we will be free one day.

This will be the day when all of God’s children will be able to sing with a new meaning, "My country, ’tis of thee, sweet land of liberty, of thee I sing. Land where my fathers died, land of the pilgrim’s pride, from every mountainside, let freedom ring."

And if America is to be a great nation this must become true. So let freedom ring from the prodigious hilltops of New Hampshire. Let freedom ring from the mighty mountains of New York. Let freedom ring from the heightening Alleghenies of Pennsylvania!

Let freedom ring from the snowcapped Rockies of Colorado!

Let freedom ring from the curvaceous peaks of California!

But not only that; let freedom ring from Stone Mountain of Georgia!

Let freedom ring from Lookout Mountain of Tennessee!

Let freedom ring from every hill and every molehill of Mississippi. From every mountainside, let freedom ring.

When we let freedom ring, whem we let it ring from every village and every hamlet, from every state and every city, we will be able to speed up that day when all of God’s children, black men and white men, Jews and Gentiles, Protestants and Catholics, will be able to join hands and sing in the words of the old Negro spiritual, "Free at last! free at last! thank God Almighty, we are free at last!"

2005年02月18日

FCKeditor 2.0 由于有了RC版
FCKeditor是sourceforge.net上最活跃的在线编辑器开源项目
从2.0开始,支持跨多浏览器: IE 5.5+, Gecko browser (Mozilla / Firefox / Netscape)
支持XHTML 1.0
服务器端接口有: ASP.Net, ASP, ColdFusion, PHP, Java

集成于Xoops的FCKeditor将随NewBB 2.0发布,详情参考
http://xoops.org.cn

November 30, 2004 – FCKeditor 2.0 RC1 released
Version 2.0 is now much more stable. People can now start thinking seriously to use it on production systems. Many bugs have been fixed and many features added: Advanced Styles (CSS integration) support with preview, Plug-ins support, HTML entities support, ASP and PHP integration modules and much more.
Go ahead! Start using FCKeditor today!

中文版下载地址:
http://xoops.org.cn/modules/wfdownloads/singlefile.php?cid=2&lid=207

打法客流量看对方开绿灯放开绿灯司法   

 Oracle的体系太庞大了,对于初学者来说,难免会有些无从下手的感觉,什么都想学,结果什么都学不好,所以把学习经验共享一下,希望让刚刚入门的人对Oracle有一个总体的认识,少走一些弯路。

一、定位

    Oracle分两大块,一块是开发,一块是管理。开发主要是写写存储过程、触发器什么的,还有就是用Oracle的Develop工具做form。有点类似于程序员,需要有较强的逻辑思维和创造能力,个人觉得会比较辛苦,是青春饭;管理则需要对Oracle数据库的原理有深刻的认识,有全局操纵的能力和紧密的思维,责任较大,因为一个小的失误就会down掉整个数据库,相对前者来说,后者更看重经验。

    因为数据库管理的责任重大,很少公司愿意请一个刚刚接触Oracle的人去管理数据库。对于刚刚毕业的年轻人来说,可以先选择做开发,有一定经验后转型,去做数据库的管理。当然,这个还是要看人个的实际情况来定。

二、学习方法

    我的方法很简单,就是:看书、思考、写笔记、做实验、再思考、再写笔记。

    看完理论的东西,自己静下心来想想,多问自己几个为什么,然后把所学和所想的知识点做个笔记;在想不通或有疑问的时候,就做做实验,想想怎么会这样,同样的,把实验的结果记下来。思考和做实验是为了深入的了解这个知识点。而做笔记的过程,也是理清自己思路的过程。

    学习的过程是使一个问题由模糊到清晰,再由清晰到模糊的过程。而每次的改变都代表着你又学到了一个新的知识点。

    学习的过程也是从点到线,从线到网,从网到面的过程。当点变成线的时候,你会有总豁然开朗的感觉。当网到面的时候,你就是高手了。

    很多网友,特别是初学的人,一碰到问题就拿到论坛上来问,在问前,你有没有查过书,自己有没有研究过,有没有搜索一下论坛?这就叫思维惰性。由别人来回答你的问题,会让你在短时间内不费劲地弄懂这个知识点,然而通过自己的努力去研究它,不但会更深入的了解这个知识点,更重要的

是在研究的过程会提高你解决问题和分析问题的能力。总的来说,没有钻研的学习态度,不管学什么东西,都不会成功的。

    当然,初学的人很多时候是因为遇到问题时,无从下手,也不知道去哪里找资料,才会到论坛上提问题的。但我认为,在提问的时候,是不是可以问别人是如何分析这个问题?从哪里可以找到相关的资料?而不是这个问题的答案是什么?授人以鱼不如授人以渔。

    下面我讲下我处理问题的过程

    首先要知道Oracle的官方网站:www.oracle.com 这里有Oracle的各种版本的数据库、应用工具和权威的官方文档。其次,还要知道http://metalink.oracle.com/这里是买了Oracle服务或是oracle的合作伙伴才可以进去的,里面有很多权威的解决方案和补丁。然后就是一些著名网站:asktom.oracle.com www.orafaq.net, www.dbazine.com。这里有很多经验之谈。

    遇到问题了。如果是概念上的问题,第一时间可以找tahiti.oracle.com,这里会给你最详细的解释。如果在运行的过程中出了什么错误。可以去metalink看看。如果是想知道事务的处理的经验之谈。可以去asktom。当然。这里只是相对而言。

三、Oracle的体系
    Oracle的体系很庞大,要学习它,首先要了解Oracle的框架。在这里,简要的讲一下Oracle的架构,让初学者对Oracle有一个整体的认识。

     1、物理结构(由控制文件、数据文件、重做日志文件、参数文件、归档文件、密码文件组成)

    控制文件:包含维护和验证数据库完整性的必要信息、例如,控制文件用于识别数据文件和重做日志文件,一个数据库至少需要一个控制文件.

    数据文件:存储数据的文件.

    重做日志文件:含对数据库所做的更改记录,这样万一出现故障可以启用数据恢复。一个数据库至少需要两个重做日志文件.

    参数文件:定义Oracle例程的特性,例如它包含调整SGA中一些内存结构大小的参数.

    归档文件:是重做日志文件的脱机副本,这些副本可能对于从介质失败中进行恢复很必要。

    密码文件:认证哪些用户有权限启动和关闭Oracle例程.


    2、逻辑结构(表空间、段、区、块)

    表空间:是数据库中的基本逻辑结构,一系列数据文件的集合。
    段:是对象在数据库中占用的空间.
    区:是为数据一次性预留的一个较大的存储空间.
    块:ORACLE最基本的存储单位,在建立数据库的时候指定.


    3、内存分配(SGA和PGA)

    SGA:是用于存储数据库信息的内存区,该信息为数据库进程所共享。它包含Oracle 服务器的数据和控制信息,它是在Oracle服务器所驻留的计算机的实际内存中得以分配,如果实际内存不够再往虚拟内存中写。

    PGA:包含单个服务器进程或单个后台进程的数据和控制信息,与几个进程共享的SGA 正相反PGA 是只被一个进程使用的区域,PGA 在创建进程时分配在终止进程时回收.

    4、后台进程(数据写进程、日志写进程、系统监控、进程监控、检查点进程、归档进程、服务进程、用户进程)

    数据写进程:负责将更改的数据从数据库缓冲区高速缓存写入数据文件
    日志写进程:将重做日志缓冲区中的更改写入在线重做日志文件
    系统监控:检查数据库的一致性如有必要还会在数据库打开时启动数据库的恢复
    进程监控:负责在一个Oracle 进程失败时清理资源
    检查点进程:负责在每当缓冲区高速缓存中的更改永久地记录在数据库中时,更新控制文件和数据文件中的数据库状态信息。
    归档进程:在每次日志切换时把已满的日志组进行备份或归档
    服务进程:用户进程服务。
    用户进程:在客户端,负责将用户的SQL语句传递给服务进程,并从服务器段拿回查询数据。

    5、Oracle例程:Oracle例程由SGA内存结构和用于管理数据库的后台进程组成。例程一次只能打开和使用一个数据库。

    6、SCN(System ChangeNumber):系统改变号,一个由系统内部维护的序列号。当系统需要更新的时候自动增加,他是系统中维持数据的一致性和顺序恢复的重要标志。

四、深入学习

    管理:可以考OCP证书,对Oracle先有一个系统的学习,然后看Oracle Concepts、Oracle online document,对oracle的原理会有更深入的了解,同时可以开始进行一些专题的研究如:RMAN、RAS、STATSPACT、DATAGUARD、TUNING、BACKUP&RECOVER等等。

    开发:对于想做Oracle开发的,在了解完Oracle基本的体系结构之后,可以重点关注PL/SQL及Oracle的开发工具这一部分。PL/SQL主要是包括怎么写SQL语句,怎么使用Oracle本身的函数,怎么写存储过程、存储函数、触发器等。 Oracle的开发工具主要就是Oracle自己的Developer Suite(Oracle Forms Developer and Reports Developer这些),学会如何熟练使用这些工具。

介绍几本oracle入门的好书

    Oracle官方文档:《concept》上面讲了oracle的体系和概念,很适合初学者看。
    OCP的教学用书,也就是STUDY GUIDE(SG)。
    Oracle8i 备份恢复手册
    Oracle8高级管理与优化
    Oracle8i PLSQL程序设计
    Oracle8数据库管理员手册
    以上书本都是机械工业出版社出版。

介绍几个网站

    http://tahiti.oracle.com oracle的官方文档

    现在http://www.oracle.com.cn/onlinedoc/index.htm也有官方文档,速度奇快

    http://metalink.oracle.com/,Oracle的技术支持网站。需要购买Oracle服务才能有一个帐号,才能登陆,有大量的Knowledge Base,大量问题解决经验。

    http://www.oracle.com oracle的官方网站,可以在这里down Oracle的软件、官方文档和获得最新的消息

    http://www.dbazine.com/ Oracle的杂志

    http://asktom.oracle.com

    http://www.orafaq.net/

    http://www.ixora.com.au/

    http://www.oracle-base.com

    http://www.dba-oracle.com/oracle_links.htm

2005年02月01日

WebLogic Server包含了Timer Service功能,你可以指定某一时刻或某一时间间隔产生Timer事件,同时你可以使用委托代理的机制,为这个事件注册事件监听器,以实现Timer Service功能。

从WebLogic Server 7.0以后的版本,WebLogic Timer Service扩展自标准的JMX Timer Service,使其可以运行于WebLogic Server的执行线程中,并且享有WebLogic Server的安全上下文环境,也就是说,可以在代码中得到安全信息,如用户名等。下面结合一个实例演示其功能。

File:TimerServiceListener.java

package org.yekki.weblogic.timer;

import java.util.Date;

import java.util.Random;

import javax.jms.JMSException;

import javax.jms.Queue;

import javax.jms.QueueConnection;

import javax.jms.QueueConnectionFactory;

import javax.jms.QueueSender;

import javax.jms.QueueSession;

import javax.jms.Session;

import javax.jms.TextMessage;

import javax.management.InstanceNotFoundException;

import javax.management.Notification;

import javax.management.NotificationListener;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.servlet.ServletContext;

import javax.servlet.ServletContextEvent;

import javax.servlet.ServletContextListener;

import org.apache.ecs.xml.XML;

import weblogic.management.timer.Timer;

public class TimerServiceListener

implements ServletContextListener, NotificationListener {

private long period;

private boolean debug;

private Timer timer;

private Integer notificationId;

private QueueConnectionFactory factory;

private QueueConnection connection;

private QueueSession session;

private QueueSender sender;

private Queue queue;

private Context ctx;

public void contextInitialized(ServletContextEvent event) {

initParams(event);

initJMS();

debug(“>>> contextInitialized called.”);

timer = new Timer();

timer.addNotificationListener(this, null, “Message Broker “);

Date timerTriggerAt = new Date((new Date()).getTime() + 5000L);

notificationId =

timer.addNotification(

“Timer Type”,

“Timer Message”,

this,

timerTriggerAt,

period);

timer.start();

debug(“>>> timer started.”);

printBrief();

}

public void initParams(ServletContextEvent event) {

ServletContext ctx = event.getServletContext();

try {

debug = Boolean.valueOf((String)ctx.getInitParameter(“debug”)).booleanValue();

}

catch (Exception e) {

debug = false;

e.printStackTrace();

}

try {

/*

second:1000L

minute:60000L

hour:3600000L

day:86400000L

week:604800000L

*/

period =

Long

.valueOf((String)ctx.getInitParameter(“period”))

.longValue();

}

catch (Exception e) {

period = Timer.ONE_MINUTE;

e.printStackTrace();

}

debug(“>>> initialized application parameters.”);

}

private void initJMS() {

try {

ctx = new InitialContext();

factory =

(QueueConnectionFactory)ctx.lookup(

“javax.jms.QueueConnectionFactory”);

queue = (Queue)ctx.lookup(“queue”);

connection = factory.createQueueConnection();

session =

connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

sender = session.createSender(queue);

connection.start();

debug(“>>> initialized jms.”);

}

catch (Exception e) {

e.printStackTrace();

}

}

public void sendMessage(String message) {

try {

TextMessage msg = session.createTextMessage();

msg.setText(message);

sender.send(msg);

debug(“>>> ################################”);

debug(“Send a message on ” + new Date());

debug(message);

debug(“>>> ################################”);

}

catch (JMSException e) {

e.printStackTrace();

}

}

public void contextDestroyed(ServletContextEvent event) {

debug(“>>> contextDestroyed called.”);

try {

timer.stop();

timer.removeNotification(notificationId);

debug(“>>> timer stopped.”);

}

catch (InstanceNotFoundException e) {

e.printStackTrace();

}

try {

if (session != null)

session.close();

if (connection != null)

connection.close();

debug(“>>> closed jms connection and session.”);

}

catch (JMSException e) {

e.printStackTrace();

}

}

private void printBrief() {

String d = “”;

d = debug ? “ON” : “OFF”;

print(“>>> ################################”);

print(“>>> Author: Niu Xiuyuan”);

print(“>>> EMail: niuxiuyuan@bea.com.cn”);

print(“>>> Company: BEA Systems”);

print(“”);

print(“>>> Debug: ” + d);

print(“>>> Period: ” + getPeriodInfo(period));

print(“>>> ################################”);

}

private void print(String str) {

System.out.println(str);

}

private String getPeriodInfo(long p) {

if (p == Timer.ONE_DAY)

return “One Day”;

if (p == Timer.ONE_HOUR)

return “One Hour”;

if (p == Timer.ONE_MINUTE)

return “One Minute”;

if (p == Timer.ONE_SECOND)

return “One Second”;

if (p == Timer.ONE_WEEK)

return “One Week”;

return “Unsupported time period!! period=” + p;

}

public void handleNotification(Notification notif, Object handback) {

Random rnd = new Random();

sendMessage(genXML(rnd.nextInt(10)));

}

public String genXML(int id) {

String username = “guru”;

String password = “niu986″;

XML usernameXML = null;

XML idXML = null;

XML passwordXML = null;

XML userXML = null;

XML profileXML = new XML(“profiles”);

for (int i = 1; i <= id; i++) {

usernameXML = (new XML("user")).addElement(username);

idXML = (new XML("id")).addElement(Integer.toString(id));

passwordXML = (new XML("password")).addElement(password);

userXML =

(new XML("user"))

.addXMLAttribute("age", "27")

.addElement(idXML)

.addElement(usernameXML)

.addElement(passwordXML);

profileXML.addElement(userXML);

}

return profileXML.toString();

}

private void debug(String msg) {

if (debug) {

System.out.println(msg);

}

}

public static void main(String[] args) {

}

}

说明:为了方便演示,此类中包含了事件产生器代码与事件监听器代码。使用ServletContextListener接口来控制Timer的启动与停止。

File:web.xml

debug false

period 60000

org.yekki.weblogic.timer.TimerServiceListener

说明:我们将webapp的Lisener注册,并且指定事件产生的时间间隔

将此WebApp部署到WebLogic Server上,然后通过中端(例如:DOS窗口)查看实验结果。

附:本例中使用了Apache的ECS项目类库,您可以访问如下URL:

http://jakarta.apache.org/ecs/index.html

2004年07月22日

一、准备篇
1 什么是J2EE?它和普通的Java有什么不同?
答:J2EE全称为Java2 Platform, Enterprise Edition。
“J2EE平台本质上是一个分布式的服务器应用程序设计环境——一个Java环境,它提供了:
·宿主应用的一个运行基础框架环境。
·一套用来创建应用的Java扩展API。”(引自《J2EE服务器端高级编程》)
2 J2EE好学吗?
答:J2EE是很多技术的集合体,并且还在成长中。
你会遇到很多专有名词:比如(X)HTML,Servlet/JSP,JDBC,JMS,JNDI,EJB,XML,Web Service……。
尤其是XML和Web Service正在快速成长。幸运的是,你不需要等到学会所有技术后再开始编程。
大体上J2EE可以分成3个主要应用:Servlet/JSP,EJB,XML/Web Service 和一些支撑技术例如JDBC和

JNDI。
你可以一个一个的学。

3 J2EE有什么用?
答:用来建设大型的分布式企业级应用程序。或者用更时髦的名词说就是“电子商务”应用程序。
这些企业可能大到拥有中心数据库服务器,Web服务器集群和遍布全国的办公终端,也可能小到只不过想

做一个网站。

4 学J2EE有前途吗?
答:在这一市场目前只有一种技术可以和J2EE竞争,那就是Microsoft的.NET。
相对来说.NET要“新”一些而J2EE要“老”一些。
但是.NET只能用于Windows平台(Microsoft声称要开发C#在Linux上的虚拟机但是尚未兑现该诺言),
考虑到Linux的发展势头,你可以相信.NET不会一统天下。

5 据说J2EE的性能不如.NET好,是真的吗?
答:在Sun公司提供的样例程序Pet Store上,Microsoft声称不如相同的.NET程序好。
而Sun公司反驳说这一程序不能真正体现J2EE的性能,并且指责Microsoft在数据库上做了优化。
作者没有学习过.NET因而不能妄下断言。
无论如何,大型分布式程序中的性能瓶颈通常首先来自于错误的设计。

6 听你说了这么多,我想学着玩玩。
答:除非你想靠它当饭吃或者作为技术储备,否则请不要浪费你的时间。
Flash要好玩得多。计算机游戏就更加好玩了。

7 学习J2EE该怎么开始?
答:首先,下载一个J2EE服务器。其次,去java.sun.com下载J2EE的API。第三,找一本好的参考书。最

后,找一个顺手的IDE。
J2EE服务器。你可以用Sun的J2EE SDK(免费),或者Weblogic(性能最好,但是太大,而且作者不推荐

盗版行为),或者JBoss(免费,就是文档太少),或者JRun(开发版免费,作者用这个)。参考书作者

感觉Wrox的《J2EE服务器端高级编程》不错,但是太老(作者手头的是2001年中文版)。你还需要去下载

一些最新的技术资料(当然肯定是英文的)。
IDE如果你的机器配置够好(内存至少512M以上,256M或以下请勿考虑),可以用IBM的WSAD,不然就继续

用Eclipse或者其他。
你也可以经常去水木清华的Java版逛逛,但是在发贴前先看看精华区里有没有你要的答案。

8 我下了一个J2EE服务器但是不会配置。
答:请认真阅读随机指导文档,不同的服务器的配置都不一样,作者爱莫能助。

9 我发现你没有提到Tomcat。
答:Tomcat只是一个Web服务器,更准确地说主要只是一个Web Container。
如果你想要学习EJB的话,Tomcat无法满足你的需要。

二、 Servlet/JSP篇

10 什么是Servlet?
答:一个Servlet是一个Java类。它处理Http(s)请求并作出响应,包括返回一个HTML页面或转交给其他

URL处理。
Servlet必须运行在一个Web Container例如Tomcat中。
Servlet必须是javax.servlet.http.HttpServlet的子类,
你可以继承doGet()或者doPost()方法,两者分别对应于Http(s)中的Get请求和Post请求。

11 我怎么获得Http请求里的参数?
答:HttpRequest的getParameter()方法。例如:String paramValue = request.getParameter

("paramName");

12 我怎么返回结果?
答:你可以利用相关API打开一个输出流,并向流中直接写入一个HTML页面。
但是作者完全不赞成这样做。一方面这样做会很罗嗦。
另一方面从Model-View-Controller模式(在《J2EE核心模式》中被归为Front Controller模式)的观点

来看,
你应当提供一些HTML或者JSP作为视图(view),而Servlet则根据请求参数决定转到哪一个视图。
你可以利用response.sendRedirect(…)方法或request.getDispatcher(…).forward()方法来实现。

13 sendRedirect()和forward()有什么不同?
答:sendRedirect()是向浏览器发送一个redirect通知,浏览器重定向到新的URL。
而forward是在服务器端直接转到新的URL,对于浏览器是透明的。
前者浏览器的地址栏显示的是新的URL,后者浏览器的地址栏显示的是Servlet的URL。
因而当目标URL会自动刷新时,两者会造成一些差别。

14 我写了一个Servlet程序,怎么运行它?
答:开发J2EE程序有一个部署(deploy)的概念,实际上是开发——部署——运行的三部曲。
大多数服务器支持Hot deploy。你只需要在相应的Application目录(具体路径依赖于服务器)下面
建立一个符合WAR或EAR格式(参见16,17)的目录,启动服务器,就可以通过浏览器访问了。
特别的,你的Servlet的class文件应当放在/WEB-INF/classes目录中。
注意J2EE SDK不支持Hot deploy,你需要通过它的deploy tool来部署。
Tomcat只支持WAR格式。

15 EAR和WAR有什么不同?
答:EAR是一个完整的J2EE应用程序,包括Web部分和EJB部分。
WAR只是其中的Web部分。

16 EAR格式是怎样的?
答:一个EAR可以包含任意多个WAR或EJB JAR,并且包含一个META-INF的目录。
在/META-INF中包含了一个application.xml,其中描述了这个EAR包含哪些模块,以及安全性配置。
细节请看参考书。

17 WAR格式是怎样的?
答:一个WAR包含一个WEB-INF的目录,这个目录下包含classes目录,lib目录和web.xml。
/WEB-INF/classes存放按package组织的class文件,/WEB-INF/lib目录存放jar文件,
web.xml描述了很多东西,请读参考书。

18 我的普通HTML文件应当放在哪里?
答:放在除了/WEB-INF以外的其他地方。

19 我访问不到servlet,甚至连HTML文件都访问不到!
答:第一你没启动服务器。第二你敲错了端口。第三你没有正确配置context-path。
第四你的服务器不支持auto reload或者你关闭了这一选项,你得重启服务器。
第五确认你没有把HTML放在/WEB-INF目录下,那是访问不到的。

20 我能访问HTML但是访问不到servlet。
答:请检查你的web.xml文件。确保你正确定义了<servlet>和<servlet-mapping>元素。
前者标识了一个servlet,后者将一个相对于context-path的URL映射到一个servlet。
在Tomcat中你可以通过/context-path/servlet/package/servletname的形式访问servlet,
但是这只是Tomcat的便捷访问方式,并不是正式规范。
细节请看参考书。

21 什么是JSP?它和Servlet有什么区别?
答:你可以将JSP当做一个可扩充的HTML来对待。
虽然在本质上JSP文件会被服务器自动翻译为相应的Servlet来执行。
可以说Servlet是面向Java程序员而JSP是面向HTML程序员的,除此之外两者功能完全等价。

22 我的JSP显示的汉字是乱码。
答:在你的JSP开头加上一行 <%@ page contentType="text/html; charset=gb2312"%>
如果你已经声明了page我想你知道该怎么修改。
23 JSP文件存放在哪里?
答:除了/WEB-INF下的任何地方。

24 在JSP里面怎么引用Java Bean。
答:首先,确认你要引用的类在/WEB-INF/classes下或在/WEB-INF/lib的某个jar内。
其次,在JSP里加一行 <jsp:useBean id="…" scope="…" class="…"/>
具体解释请看参考书。

25 我想在servlet间传递数据。
答:利用session。在Servlet/JSP中,你可以在4个地方保存数据。
1) page,本页面。
2) session,用来存放客户相关的信息,比如购物车,对应接口为javax.servlet.http.HttpSession。
session机制实际上是cookie和URL Rewrite的抽象,服务器会自动使用cookie或URL Rewrite来实现。
3) request,可以在forward()时传递信息,对应接口为javax.servlet.http.HttpRequest。
4) application,或称context,存放全局信息,对应接口为javax.servlet.ServletContext。

26 怎么调用cookie?
答:作者建议使用session,你总是会遇到某些禁用cookie的用户。这时session会自动使用URL重写来实

现。

27 怎么在JSP里面实现文件下载?
答:实际上这是一个HTML的问题。答案是一个超链接<a>。

28 怎么实现文件上传?
答:客户端是HTML问题,在form中设置method为post,enctype为multi-part/form-data,加一个<input

type="file">。
而在接收的servlet中只是一个I/O问题。

29 我想让页面自动刷新,比如聊天室。
答:这是一个HTML问题,在<head>部分中加一条<meta http-equiv="refresh" content="5" url="…">


这是所谓的Clinet-push,客户端刷新技术。

30 我想让用户登录以后才能访问页面。
答:使用声明式安全措施。
你只需要在web.xml中定义安全角色(Role),并定义受保护的URL集合只能由特定Role访问。
大多数服务器支持基于数据库的用户映射,你只要在相应数据库中建立两张表并配置服务器就可以了。
注意J2EE SDK不支持基于数据库的用户映射。
细节请看参考书和服务器文档。

31 我想要能注册用户。
答:参看30。在接受注册请求的Servlet中执行写入数据库操作即可。

32 怎么在JSP中访问数据库?
答:标准做法是使用DAO模式,定义一个Java bean来访问数据库并在JSP中使用。
然而,当你的数据库模式很简单时,你可以使用JSTL中的<sql:query>标签来快速访问。

33 什么是JSTL?
答:JSTL是Jsp Standard Tag Library的缩写。这是一组通用标签并将成为JSP 2.0的一部分。
其中包含赋值<c:set>,分支<c:if>,循环<c:forEach>,查询数据库<sql:query>,更新数据库

<sql:update>
等。目前你需要像添加自定义标签库一样来添加JSTL,但是可以预计JSP 2.0会将JSTL作为组成部分。
标签库可以在http://jakarta.apache.org下载。注意JSTL需要在支持JSP1.2或更高版本的容器下运行。

  实战java发邮件     petehero [原作]
关键字   实战java发邮件
出处  

必须下载sun公司的JavaMail API包,地址为:http://java.sun.com/products/javamail/ 并将相关包(jar文件)加到CLASSPATH中。
或者如果安装j2ee则将j2ee.jar加入classpath即可。

源程序如下,替换红色部分即可使用。

对您有帮助或有问题请来信讨论:petehero@126.com

 

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;

/**
 * <p>Title: java mail</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2004</p>
 * <p>Company: </p>
 * @author petehero
 * @version 1.0
 */

public class SendMail
{

    public SendMail()
    {
    }
    public void send(){
        try
        {
            Properties props = new Properties();
            Session sendMailSession;
            Store store;
            Transport transport;
            props.put(“mail.smtp.auth”,”true”);
            props.put(“mail.smtp.host”, “smtp.yourmail.com“); //smtp主机名。
            props.put(“mail.smtp.user”,”username@yourmail.com“); //发送方邮件地址。
            props.put(“mail.smtp.password”,”888888“); //邮件密码。
            PopupAuthenticator popA=new PopupAuthenticator();//邮件安全认证。
            PasswordAuthentication pop = popA.performCheck(“username“,”888888“); //填写用户名及密码
            sendMailSession = Session.getInstance(props, popA);
            Message newMessage = new MimeMessage(sendMailSession);
            newMessage.setFrom(new InternetAddress(“username@yourmail.com“));
            newMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(“receiver@mail.com“));  //接收方邮件地址
            newMessage.setSubject(“邮件主题”);
            newMessage.setSentDate(new Date());
            String mailContent;
            mailContent=”你好!\n\n”;
            mailContent+=”\t邮件正文\n\n”;
            mailContent+=new Date().toLocaleString();
            newMessage.setText(mailContent); //邮件正文
            transport = sendMailSession.getTransport(“smtp”);
            transport.send(newMessage);
        }
        catch (MessagingException ex)
        {
            ex.printStackTrace();
        }
    }
    public static void main(String[] args)
    {
        SendMail sml = new SendMail();
        sml.send();
    }

    public class PopupAuthenticator extends Authenticator{
        String username=null;
        String password=null;
        public PopupAuthenticator(){}
        public PasswordAuthentication performCheck(String user,String pass){
            username = user;
            password = pass;
            return getPasswordAuthentication();
        }
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(username, password);
        }

    }
}

 

 

下载
Eclipse及其语言包下载
下载地址:http://www.eclipse.org/downloads/   。有各种平台版本的,我们选windows平台的下,具体如下:
Eclipse :Eclipse SDK for windows  
版 本:2.1.3   
文件名:eclipse-SDK-2.1.3-win32.zip
语言包:Language Pack 
版 本:2.1.2_Translations
文件名:eclipse2.1.2.1-SDK-win32-LanguagePackFeature.zip
注:虽然语言包是for 2.1.2版的但在Eclipse2.1.3版一样可以使用,而且不会影响Eclipse的使用稳定性,因为语言包都是一些将界面文字翻译成各国文字的文本文件,并不涉及到程序的改动。不过我试过这个语言包在Eclipse M3.X下无法试用(只能将个别词翻译过来),看来Eclilpse 3更动还是挺大的。
 
2004年07月21日

如果您曾想过构建自己的超级计算机,但却对用 C 语言进行并行编程望而生畏,那么伪远程线程可以帮您解决这一问题。这种获奖的 Java 编程模型极大地简化了集群上的并行编程,并使超级计算走出实验室,使每一位 Java 程序员都能使用它。
在过去的三年里,并行集群已在改变着超级计算的面貌。一旦价值数百万美元的单体机占了主导,并行集群很快就会成为超级计算机的选择。可以想像得到,开放源码圈内的高涨热情已导致产生了数百 — 如果不是数千的话 — 并行集群项目。第一个同时也是最著名的开放源码集群系统是 Beowulf。在 NASA 赞助下,由 Thomas Sterling 和 Donald Becker 在 1994 年发布的 Beowulf,开始是作为一个 16 节点演示集群推出的。今天,Beowulf 已有数百种实现,从 Oak Ridge 国家实验室的 Stone SouperComputer 到 Aspen 系统公司的定制构建的商业性集群(请参阅参考资源)。

对 Java 程序员不利的是,多数集群系统都是围绕基于 C 语言的软件消息传递 API — 如消息传递接口(MPI)或并行虚拟机(PVM)— 来实现的。用 C 语言进行并行编程不是件容易的事,因此我设计了一个替代方案。本文将说明如何综合运用 Java 线程和 Java 远程方法调用(RMI)来创建自己的基于 Java 的超级计算机。

请注意,本文假定您有 Java 线程和 RMI 的应用知识。

超级计算机内有什么?
超级计算机的定义是:由八个或更多的节点组成、作为单个高性能机器工作的集群。基于 Java 的超级计算机包含一个作业调度器和任意数量的运行服务器(也称为主机)。作业调度器生成多个线程,每个线程包含执行不同子任务的代码。各个线程将其代码迁移到不同的运行服务器上。然后,每个运行服务器执行迁移给它的代码并将结果返回给作业调度器。最后,作业调度器将各个线程的结果组合起来。

这种并行集群系统之所以被称为伪远程线程,是因为线程是在作业调度器上调度的,但线程内的代码却是在远程计算机上执行的。

该系统有哪些组件?
组件一词是指组成“伪远程线程”并行集群系统的逻辑模块。该系统包含以下组件:

Job dispatcher(作业调度器) 是执行控制的机器。它生成不同的线程,每个线程都包含此集群要处理的主任务的一个子任务。每个线程内的代码都被发送到一台远程计算机去执行。线程在作业调度器上调度,所以理论上讲,该机器不应该用于执行任何子任务。

SubTask 是一个用户定义类,该类定义主任务的一个数据或功能独立的部分。您可以为主任务的不同部分定义不同的类。类名 SubTask 是一个示例。您可以为一个 SubTask 类取任何名字,不过这个名字应该能描述分配给它的子任务。在定义 SubTask 类时,您必须实现 JobCodeInt 接口以及 jobCode() 方法,下面对其进行说明。

JobCodeInt 是一个 Java 接口。您必须在定义子任务的类中实现该接口和 jobCode() 方法。jobCode() 方法描述了将在远程执行的代码。如果您打算在远程使用某个本地资源,您必须在 jobCode() 方法外部初始化这个资源。比方说,您要将一组图像发送到远程处理,就必须在 jobCode() 方法外部初始化 Image 对象。您可以在该方法中调用标准 Java 库中的类,因为远程计算机上存在这些库。

RunServer 是一个 Java 对象,该对象允许远程过程调用其方法。它的一个方法以实现了 JobCodeInt 接口的对象作为参数。 RunServer 就在运行该对象的计算机(运行服务器)上执行该对象内的代码,并将计算结果作为 Object 类的一个实例返回。Object 是 Java 类层次结构中最高一级的类。

PseudoRemThr 是一个 Java 类,该类封装了一个线程并接受给定 SubTask 类的一个实例。它选择一台远程主机,并将 SubTask 实例发送到这台主机上执行。如果您要利用某台主机上可用的特定资源(诸如数据库或是打印机),则可以指定主机。

HostSelector 是一个模块。如果您没有指定远程主机,PseudoRemThr 类就会调用 HostSelector 模块来选择特定的主机。如果没有空闲的主机,HostSelector 会返回负载最小的远程计算机。如果某个远程计算机是一个多处理器系统,HostSelector 可能会不止一次地返回该主机名。目前,HostSelector 无法根据给定任务的复杂程度来选择主机。
伪远程线程的工作方式
要使用伪远程线程,您必须实现作业调度器和运行服务器。本节将说明如何实现各个部分。

实现作业调度器
首先,将主任务分解为数据或功能独立的子任务。针对每个子任务,定义一个实现 JobCodeInt 接口(从而实现 jobCode() 方法)的类。在 jobCode() 方法中,定义各给定子任务要执行的代码。

请注意,您不能调用作业调度器上用户定义的的本地资源。请在该方法外部初始化所有这类资源。例如,您可以在 SubTask 类的构造函数中初始化这类资源。

创建类 PseudoRemThr 的若干实例,并将 SubTask 的实例传递给 PseudoRemThr 的各个实例。如果您要明确指定一台远程主机,您可以通过调用 PseudoRemThr 对象的另一个构造函数来完成。

等待这些线程完成。调用 getResult() 方法来获取 PseudoRemThr 的各个实例的执行结果。如果计算没有完成,结果返回一个值为 false 的 Boolean 对象;否则,将返回 Object 类的一个实例,其中包含了计算结果。您必须将此实例转换为您所希望的类类型。将所有的子任务结果组合为最终结果。

实现运行服务器
实现运行服务器是一项简单的工作:

启动 RMI 注册程序。
启动 RunServer。
运行服务器在启动时接通作业调度器,并通知作业调度器它已准备就绪,可以接受要执行的任务了。

一个计算示例
现在该测试这一模型了。以下计算示例使用两台计算机并行运行。一台是运行 Windows 98 的 333 MHz Pentium II 计算机,另一台是运行 Windows 2000 专业版的 500 MHz Pentium III 计算机。

为了计算从 1 到 10^9 的所有整数的平方根之和,我创建了 Sqrt 类,它计算 dblStart 和 dblEnd 之间所有整数的平方根之和。

Sqrt 实现 JobCodeInt 接口,因此也实现了 jobCode() 方法。在 jobCode() 方法中,我定义了完成这一计算的代码。

构造函数用于将数据传递给 Sqrt 类,并初始化作业调度器上的所有本地资源。必须将要计算其平方根之和的整数的起止点发送给构造函数。清单 1 是 Sqrt 类的定义

清单 1. 定义 Sqrt 类

//Sqrt 类计算 dblStart 和 dblEnd 之间的所有整数的平方根之和。
//计算在 jobCode() 方法内完成
//该类实现 JobCodeInt 接口,且实现代码位于 jobCode() 方法内
//在构造函数中将数据传递给该类,并初始化作业调度器上的本地资源。
//本例中,要计算其平方根之和的整数序列的起止点被发送给 Sqrt 类
public class Sqrt implements JobCodeInt
{

double dblStart, dblEnd, dblPartialSum;

public Sqrt(double Start,double End)
{
dblStart = Start;
dblEnd = End;
}

public Object jobCode()
{
dblPartialSum = 0;
for(double i=dblStart;i<=dblEnd;i++)
//可调用标准的 Java 函数和对象。
dblPartialSum += Math.sqrt(i);

//返回结果,一个标准 Java 类的对象。
return (new Double(dblPartialSum));
}
}

JobDispatcher 类创建 Sqrt 类的两个实例。然后分解主任务,将一项子任务分配给一个 Sqrt 对象(Sqrt1),并将余下的子任务分配给另一个 Sqrt 对象(Sqrt2)。接下来,JobDispatcher 创建 PseudoRemThr 类的两个对象,并将 Sqrt 对象作为参数分别传递给它们。接下来就等待线程执行。

一旦线程执行完毕,就可从每个 PseudoRemThr 实例获得部分结果。将各部分结果组合起来即可得到最终结果,如清单 2 所示。

清单 2. 工作中的 JobDispatcher

//此类可以命名为您选择的任何名称
//这里选用 JobDispatcher 只是为了方便

public class JobDispatcher
{
public static void main(String args[])
{
double fin = 10000000; //代表 10^9
double finByTen = fin/10; //代表 10^8
long nlStartTime = System.currentTimeMillis();
//范围从 1 到 3*10^8
Sqrt sqrt1 = new Sqrt(1,finByTen*3);
//范围从 ((3*10^8)+1) 到 10^9
Sqrt sqrt2 = new Sqrt((finByTen*3)+1,fin);

//以下创建 PseudoRemThr 类的两个实例。 //此构造函数的参数如下所示。 //第一个参数:代表子任务的某个类的实例
//第二个参数:执行这一子任务的远程主机
//第三个参数:PseudoRemThr 实例的描述性名称。
PseudoRemThr psr1 = new
PseudoRemThr(sqrt1,”//192.168.1.1:3333/”,”Win98″);
PseudoRemThr psr2 = new
PseudoRemThr(sqrt2,”//192.168.1.2:3333/”,”Win2K”);

psr1.waitForResult(); //等待执行结束//获取每个线程的结果
Double res1 = (Double)psr1.getResult();
Double res2 = (Double)psr2.getResult();
double finalRes = res1.doubleValue() + res2.doubleValue();

long nlEndTime = System.currentTimeMillis();
System.out.println(“Total time taken: ” + (nlEndTime-nlStartTime));
System.out.println(“Sum: ” + finalRes);
}
}

性能评价
此计算的总执行时间在 120,000 毫秒到 128,000 毫秒之间。如果在不分解任务的情况下在本地运行同样的任务,执行时间将在 183,241 到 237,641 毫秒之间。

最初,主任务包括计算从 1 到 10^7 的所有整数的平方根之和。为测试性能,我将计算范围扩大到 10^8,最终扩大到 10^9。

随着任务量的增加,远程并行执行和本地执行所需时间的差别也越来越明显。这就是说,当执行大型任务时,远程并行执行消耗的时间较少。远程并行执行并不适合小型任务,因为机器间通信的系统开销不容忽视。随着任务量的增加,机器间通信的开销与在单个机器上执行全部任务的开销相比逐渐变得微不足道。因此,我得出以下结论:伪远程线程系统能很好地完成需要进行大量计算的任务。

使用伪远程线程有哪些优点?
因为伪远程线程是一种基于 Java 的系统,它可以用于实现包含多种操作系统的集群,或异构集群。使用伪远程线程,您就避免了转换原有 C/C++ 代码的麻烦,而且还能利用 Java 标准库及其各种扩展库。此外,伪远程线程使您不必关心内存管理。当然,其缺点就是系统性能与 JRE 性能直接相关。

发展方向
现在相当多的商业应用程序都是用 Java 平台创建的,并考虑到为了利用并行性需要转换原有的 C/C++ 代码的实际困难,现在可能是基于 Java 的超级计算进入商业领域的时候了。在开始创建基于 Java 的应用程序时就将并行性和负载均衡考虑在内是个不错的开端。

互联网就是异构集群的一个很好的例子,因此伪远程线程可以在因特网中部署,将 Web 转换为一个单一的、基于 Java 的超级计算机(要了解这一概念的细节,请参阅参考资源)。然而,从实际应用出发,您应注意到在一个专门执行单一任务的同构集群中将获得最佳结果。

最后,从日常应用出发,伪远程线程使得将局域网(LAN)– 诸如校园网和家庭网 — 转换为微型的超级计算机变得相当简单。这就是 Beowulf 系统开创的用法。有了伪远程线程,Java 编程人员也可以创建自己的超级计算机了。

参考资源

“Linux clustering cornucopia”(developerWorks, 2000 年 5 月)为您指点迷津,让您了解当前 Linux 上可用的开放源码集群解决方案和保密源码集群解决方案。

要了解关于分布式操作系统的详细信息,请查看 Andrew S. Tanenbaum 的 Modern Operating Systems(Prentice Hall 出版公司,1992 年 2 月)。

要了解关于并行编程的详细信息,请参阅 Gregory V. Wilson 的 Practical Parallel Programming(麻省理工学院出版社,1995 年 12 月)。

要进一步理解集群,请参阅 Scalable Computing Laboratory 的 Cluster Cookbook。

有关运用 Java 技术和 Web 进行超级计算的深层探讨,请参阅 Laurence Vanhelsuw 的 “Create your own supercomputer with Java?”(JavaWorld, 1997 年 1 月)。

Linux Documentation Project 托管着 Beowulf HOWTO 文档。

访问 Beowulf 网站,以了解 Beowulf 项目的详细信息。

请参阅关于 Oak Ridge 国家实验室著名的 Stone SouperComputer 的详细信息。

Aspen 系统公司是目前提供定制集群解决方案的少数厂商之一。

如果你正在负责一个基于SQL Server的项目,或者你刚刚接触SQL Server,你都有可能要面临一些数据库性能的问题,这篇文章会为你提供一些有用的指导(其中大多数也可以用于其它的DBMS)。

在这里,我不打算介绍使用SQL Server的窍门,也不能提供一个包治百病的方案,我所做的是总结一些经验—-关于如何形成一个好的设计。这些经验来自我过去几年中经受的教训,一直来,我看到许多同样的设计错误被一次又一次的重复。

你了解你用的工具吗?

不要轻视这一点,这是我在这篇文章中讲述的最关键的一条。也许你也看到有很多的SQL Server程序员没有掌握全部的T-SQL命令和SQL Server提供的那些有用的工具。

“什么?我要浪费一个月的时间来学习那些我永远也不会用到的SQL命令???”,你也许会这样说。对的,你不需要这样做。但是你应该用一个周末浏览所有的T-SQL命令。在这里,你的任务是了解,将来,当你设计一个查询时,你会记起来:“对了,这里有一个命令可以完全实现我需要的功能”,于是,到MSDN查看这个命令的确切语法。

不要使用游标

让我再重复一遍:不要使用游标。如果你想破坏整个系统的性能的话,它们倒是你最有效的首选办法。大多数的初学者都使用游标,而没有意识到它们对性能造成的影响。它们占用内存,还用它们那些不可思议的方式锁定表,另外,它们简直就像蜗牛。而最糟糕的是,它们可以使你的DBA所能做的一切性能优化等于没做。不知你是否知道每执行一次FETCH就等于执行一次SELECT命令?这意味着如果你的游标有10000条记录,它将执行10000次SELECT!如果你使用一组SELECT、UPDATE或者DELETE来完成相应的工作,那将有效率的多。

初学者一般认为使用游标是一种比较熟悉和舒适的编程方式,可很不幸,这会导致糟糕的性能。显然,SQL的总体目的是你要实现什么,而不是怎样实现。

我曾经用T-SQL重写了一个基于游标的存储过程,那个表只有100,000条记录,原来的存储过程用了40分钟才执行完毕,而新的存储过程只用了10秒钟。在这里,我想你应该可以看到一个不称职的程序员究竟在干了什么!!!

我们可以写一个小程序来取得和处理数据并且更新数据库,这样做有时会更有效。记住:对于循环,T-SQL无能为力。

我再重新提醒一下:使用游标没有好处。除了DBA的工作外,我从来没有看到过使用游标可以有效的完成任何工作。

规范化你的数据表

为什么不规范化数据库?大概有两个借口:出于性能的考虑和纯粹因为懒惰。至于第二点,你迟早得为此付出代价。而关于性能的问题,你不需要优化根本就不慢的东西。我经常看到一些程序员“反规范化”数据库,他们的理由是“原来的设计太慢了”,可结果却常常是他们让系统更慢了。DBMS被设计用来处理规范数据库的,因此,记住:按照规范化的要求设计数据库。

不要使用SELECT *

这点不太容易做到,我太了解了,因为我自己就经常这样干。可是,如果在SELECT中指定你所需要的列,那将会带来以下的好处:

1 减少内存耗费和网络的带宽

2 你可以得到更安全的设计

3 给查询优化器机会从索引读取所有需要的列

了解你将要对数据进行的操作

为你的数据库创建一个健壮的索引,那可是功德一件。可要做到这一点简直就是一门艺术。每当你为一个表添加一个索引,SELECT会更快了,可INSERT和DELETE却大大的变慢了,因为创建了维护索引需要许多额外的工作。显然,这里问题的关键是:你要对这张表进行什么样的操作。这个问题不太好把握,特别是涉及DELETE和UPDATE时,因为这些语句经常在WHERE部分包含SELECT命令。

不要给“性别”列创建索引

首先,我们必须了解索引是如何加速对表的访问的。你可以将索引理解为基于一定的标准上对表进行划分的一种方式。如果你给类似于“性别”这样的列创建了一个索引,你仅仅是将表划分为两部分:男和女。你在处理一个有1,000,000条记录的表,这样的划分有什么意义?记住:维护索引是比较费时的。当你设计索引时,请遵循这样的规则:根据列可能包含不同内容的数目从多到少排列,比如:姓名+省份+性别。

使用事务

请使用事务,特别是当查询比较耗时。如果系统出现问题,这样做会救你一命的。一般有些经验的程序员都有体会—–你经常会碰到一些不可预料的情况会导致存储过程崩溃。

小心死锁

按照一定的次序来访问你的表。如果你先锁住表A,再锁住表B,那么在所有的存储过程中都要按照这个顺序来锁定它们。如果你(不经意的)某个存储过程中先锁定表B,再锁定表A,这可能就会导致一个死锁。如果锁定顺序没有被预先详细的设计好,死锁是不太容易被发现的。

不要打开大的数据集

在CSDN技术论坛中 :),一个经常被提出的问题是:我怎样才能迅速的将100000条记录添加到ComboBox中?这是不对的,你不能也不需要这样做。很简单,你的用户要浏览100000条记录才能找到需要的记录,他一定会诅咒你的。在这里,你需要的是一个更好的UI,你需要为你的用户显示不超过100或200条记录。

不要使用服务器端游标

与服务器端游标比起来,客户端游标可以减少服务器和网络的系统开销,并且还减少锁定时间。

使用参数查询

有时,我在CSDN技术论坛看到类似这样的问题:“SELECT * FROM a WHERE a.id=’A'B,因为单引号查询发生异常,我该怎么办?”,而普遍的回答是:用两个单引号代替单引号。这是错误的。这样治标不治本,因为你还会在其他一些字符上遇到这样的问题,更何况这样会导致严重的bug,除此以外,这样做还会使SQL Server的缓冲系统无法发挥应有的作用。使用参数查询, 釜底抽薪,这些问题统统不存在了。

在程序编码时使用大数据量的数据库

程序员在开发中使用的测试数据库一般数据量都不大,可经常的是最终用户的数据量都很大。我们通常的做法是不对的,原因很简单:现在硬盘不是很贵,可为什么性能问题却要等到已经无可挽回的时候才被注意呢?

不要使用INSERT导入大批的数据

请不要这样做,除非那是必须的。使用UTS或者BCP,这样你可以一举而兼得灵活性和速度。

注意超时问题

查询数据库时,一般数据库的缺省都比较小,比如15秒或者30秒。而有些查询运行时间要比这长,特别是当数据库的数据量不断变大时。

不要忽略同时修改同一记录的问题

有时候,两个用户会同时修改同一记录,这样,后一个修改者修改了前一个修改者的操作,某些更新就会丢失。处理这种情况不是很难:创建一个timestamp字段,在写入前检查它,如果允许,就合并修改,如果存在冲突,提示用户。

在细节表中插入纪录时,不要在主表执行SELECT MAX(ID)

这是一个普遍的错误,当两个用户在同一时间插入数据时,这会导致错误。你可以使用SCOPE_IDENTITY,IDENT_CURRENT和@@IDENTITY。如果可能,不要使用@@IDENTITY,因为在有触发器的情况下,它会引起一些问题(详见这里的讨论)。

避免将列设为NULLable

如果可能的话,你应该避免将列设为NULLable。系统会为NULLable列的每一行分配一个额外的字节,查询时会带来更多的系统开销。另外,将列设为NULLable使编码变得复杂,因为每一次访问这些列时都必须先进行检查。

我并不是说NULLS是麻烦的根源,尽管有些人这样认为。我认为如果你的业务规则中允许“空数据”,那么,将列设为NULLable有时会发挥很好的作用,但是,如果在类似下面的情况中使用NULLable,那简直就是自讨苦吃。

CustomerName1

CustomerAddress1

CustomerEmail1

CustomerName2

CustomerAddress2

CustomerEmail3

CustomerName1

CustomerAddress2

CustomerEmail3

如果出现这种情况,你需要规范化你的表了。

尽量不要使用TEXT数据类型

除非你使用TEXT处理一个很大的数据,否则不要使用它。因为它不易于查询,速度慢,用的不好还会浪费大量的空间。一般的,VARCHAR可以更好的处理你的数据。

尽量不要使用临时表

尽量不要使用临时表,除非你必须这样做。一般使用子查询可以代替临时表。使用临时表会带来系统开销,如果你是用COM+进行编程,它还会给你带来很大的麻烦,因为COM+使用数据库连接池而临时表却自始至终都存在。SQL Server提供了一些替代方案,比如Table数据类型。

学会分析查询

SQL Server查询分析器是你的好伙伴,通过它你可以了解查询和索引是如何影响性能的。

使用参照完整性

定义主健、唯一性约束和外键,这样做可以节约大量的时间。