随笔-20  评论-2  文章-0  trackbacks-0
 

【第一篇】

我是如何提高口语水平的?


   首先、确定你自己的英语水平。中国大学毕业生的通病是,书面阅读还可以,口语不行,听力很差,书写凑合。但每个人具体情况又都不一样,有人阅读专业书一目 十行,但读报纸很费劲。有人听新闻可以,听别的不行。你必须首先了解自己,然后针对你的情况对症下药。这种评估工作最好找英语好的人帮你做,如果不方便, 只能自己评自己,就要尽量做到客观。

  其次、确定自己的发音水平。我有个朋友对我说他的发音没问题,可实际上他说得很多词我都听不懂。你学的是英国音还 是美国音都无所谓,反正最终从你嘴里出来的肯定是中国音。最重要的是发音要合理。英语每一个单词都有自己的念法,你不能凭空想象。比如,有人把 RESUME读做RE-'SOOM,这样,别人说RE-SIU-'MAY,你不知道是什么。你念RE-'SOOM,别人也听不懂。再次、确定自己的英语学 习目标。我这里仅把口语交流做为目标。最后、开始学习。

1、口语学习的关键是要模仿人家的说话。这包括语音和语调两部分。中国英语教学重视语调的很少,尽管很多时候语调可能比语音更重要。

2、买一台录音机,找一合磁带。根据你的水平,可以选择新概念第二或第三册,也可以到图书馆借一套有书和磁带的小故事集。注意:一定要有书,故事篇幅不能太长,生词量要小,过于简单没有关系。我倾向于使用故事,而不是对话或新闻听力材料。

3、进行跟读训练。放磁带,看着书,搞明白每一个单词的意思,理解整个故事情节。然后,放一句,暂停,学着人家读一句,然后,放下一句,暂停,再学一句,继续。

4、跟读过程中要注意的几点:

(1)一定要尽力模仿发音和语调,越象越好。

(2)开始时速度可以比较慢,要逐步使自己跟上人家的速度。

(3)中间可以回倒重放,但我倾向于让大家完成一小段后再回去重来。

5、同步阅读。当你对文章发音、语调完全掌握之后,就要在放录音的同时同步跟读。争取让自己的声音与他完全重合。注意语调和语音。如果中间有结巴的地方也不要紧,继续读下去,然后再回来重读。

6、关掉录音机,朗诵课文。注意使用学到的语音语调。带滚瓜烂熟之后,可以进入下一篇课文。

  这样,一两个月之后,当你“精读”过五到十篇约一千字篇幅的文章之后,你会发现你的英语发音和听力有了明显的进步。再配合其他学习,如与人聊天,看电视,听广播,等等,口语水平会得到显著提高。

【第二篇】

         英语作为一种工具,其实用性愈显重要。传统英语教育方法由于过于艰深化,以及盲目的应试模式使大部分的英语学习者学了几年甚至数十年,却仍然处于听不懂开不了口的尴尬境地。那么究竟如何才能在比较短的时间里快速提高口语水平,让她真正为你所用呢?
   西方最新流行一种外语学习理论,即口语提高的最好方式就是采用短期突破法。从下面的公式中,就可以看出,口语短期突破的方法是很有效的。
  口语提高速度定律=说英语时间/说中文时间Speed of learning English=Speaking English/Speaking Chinese ( in a period of time)
  比如,在给定的一天时间内(16小时),学生A练习英语口语的时间为14小时,说中文的时间为2小时,两者的比例为7:1;学生B练习口语的时间为2 小时英语,说中文的时间为14小时。比例为1:7。如此一来,学生A比学生B说英语的比例大49倍。
  我们认为:这一理论其实就是对语言学习规律一次很好的回归,语言的核心是使用者能够随时随地地使用它。你用的时间越长,你就越熟练,这里我们说的使用 就是“说”,用嘴巴表达出来,而不是用眼睛和脑子去看和死记。如果你能够在一段时间内的大部分时间里坚持持续使用英语而不是中文进行表达,把学习英语的任 务转化成母语似的说话习惯,你就完全可以在很短的时间内有效掌握一口流利的英语口语。
  当然现实情况却是:很多人并没有这样的勇气和能力去坚持使用一个完全不熟悉的语言进行日常的交流!所以选用一套优秀的教材和相应的工具就显得异常重要了,这种教材应该具备以下特点才能帮助你克服困难:
  1、能够随时随地学习,让你很容易就接触到英语;
  2、能够让你脱离书本,完全浸在英语环境里;
  3、内容应该精挑细选,具备典型性和代表性,帮助你在短时间内掌握精华内容,从而建立起长期学习的信心和基本能力。
  同时你应该注意培养自己的自信,学会勇敢犯错误,克服恐惧的心理障碍。其实这种心理障碍是成人自己加给自己的,为什么我们小时候学母语这么自然容易,就是因为那个时候不知道什么是丢脸。所以我们应该象小时候那样暂时忘却丢脸,勇敢地去丢脸!

【第三篇】

想提高英语口语水平,首先要在语音上下功夫:)~
下面是些方法,你可以根据自己的学习方式掌握:)~

1.其次,要有大量的阅读和听力做基础。在读和听的过程中,积累了词汇,掌握了句型,熟悉了用英语表达思想的方式,最重要的是培养了语感。

2.同时,学英语口语也需要用多种办法:如大声朗读英语对话和文章,朗读各种句型的例句和口语中最常用的句子,背诵文章及演讲,与会英语的人练口语,当 然,最好与以英语为母语的人练口语。事实上,自言自语亦是练习口语的有效的方法之一。如果你把自己说的英语给录制下来,听听自己的录音,若有问题,再加以 改正,效果就会更好。

3.说英语还要有胆量。如果你能在说不太出口,或是说不好的情况下,大胆地说。说上一段时间后,突然有一天你会自如、清楚地表达自己的思想。有了大胆说的精神,你才能闯过口语的难关。

4.只会学英语,而不能尽快地去用,那就永远也学不好英语。在学英语的过程中,要始终寻找机会说英语。比如说,你周围有几个喜欢说英语的朋友,大家在一起 就要用英语来交谈。这种交谈有利于每个人的英语学习,因为大家都有机会运用自己已掌握的英语知识来交流思想,巩固了已学的知识,并把知识转化成技能,同 时,还能从别人那儿学到新的东西。要想学好英语口语就要多说。

5.能同以英语为母语的人说英语是最佳方法。在国内学英语缺乏环境,看电影学英语口语是弥补环境不足的好方法。英语电影是一部英语国家的生活、文化、风俗 等一切的百科全书,是最全的英语口语百科全书。大量地看英文电影就是你彻底攻克英语“听”和“说”的法宝。英语电影把你带入了一个新的世界中去。你在电影 中,学到了英语口语的语汇、短语、句子结构,以及表达各种内容的说法。你要做的就是把自己想像成电影中的一个角色,在经历着自己的生活,又在经历着其他人 的生活。总之,看一部电影比在美国生活一天还好,看电影也能学到地道的英语口语。

【第四篇】

当代社会是个开放社会,信息社会,人们越来越重视交际,而我国改革开放的成功也日益提高了我国在世界上的地位,我们与世界各国交流的领域越来越广了,没有出众的英语口语表达将会寸步难行。
  而要提高英语口语表达能力,就要先了解英语口语表达的过程是怎样发生的。大家知道,语言是思维的外壳。口语表达的过程,实际上是一个复杂的心理和生理过程,是思维借助词语按一定句式迅速转换为有声言语的过程。因此,口语能力的强弱取决于:
  1、思维能力的强弱,特别是与口语有关的思维的条理性、敏锐性与灵活性,这是关键。
  2、准确、迅速地组织言语(选词、造句、组段、构篇)能力的强弱,这是基础。
  3、运用语言的能力的强弱,这是前提。
  根据口语表达循序渐进的一般规律,口语训练的重点应是培养敏锐的思维和强烈的语感。具体包括:
  1、语音。学会科学发声方法,能用准确、响亮、流畅的英语进行口头表达。
  2、语调。能借助声音高低升降、抑扬顿挫的变化来表达复杂的感情,掌握停连和轻重、抑扬和明暗、快慢和松紧等一般的朗读技巧。
  3、词汇。能掌握比较丰富的口语词汇。
  4、语脉。说话能做到有条有理、语言流畅、上下贯通、一脉相承。
  5、语境。说话注意目的、对象、场合,合乎规定情景的要求,讲礼貌、有针对性。懂得口语修辞。在会话中有随机应变的能力。
  此外,还要懂得口头言语的辅助手段--表情、姿势、动作等态势言语的运用。
  由于书面语和口语是相互渗透、相互促进的,为提高口语的表现力,可在说话训练之前先进行一章朗读、朗诵训练。听和说是一个事物的两个方面,吸收、表达 两者不能偏废,所以口语训练体系中也应包括。通过以上训练,掌握一定的朗读朗诵技巧,培养准确、流利、有感情地朗读朗诵一般作品的能力,特别注意培养强烈 的语感。
  3、听力训练
  培养听的注意力、理解力、记忆力和辨析力,提高听知能力,养成良好的听的习惯。
  4、口语表达基本方式训练
  进行叙述、描述、评述、解说等口语表达基本方式的训练,培养内部言语向外部言语迅速转化的能力,结合进行语调、语脉的训练。
  5、会话型言语训练
  言语形式有会话型和独白型两类。会话是指两个以上的人围绕一个或几个话题一起说话的形式,如交谈、座谈、辩论、审讯等。会话时参加者是互为听、讲者 的,因此后面的发言常常受到前面发言的制约。另外,由于当面交谈,大量态势语代替了言语表达,会话者的言语结构往往不严谨、不完善,省略句较多。
  可进行如下训练:通过交谈和辩论两种会话言语训练,了解它们的一般特点、注意事项,结合进行应变能力和礼貌用语的训练,从而在会话中有效地培养随机应变的能力。
  6、独白型言语训练
  独白是指一个人单独发言而其他人都作为听众的言语表达形式,如:讲故事、作报告、讲课、演讲、讲解员的解说等。独白言语一般不在进行过程中跟听众问答 交流,因此要求在事先要周密地了解听众的要求并系统地组织好发言内容和有关态势语。独白是一种高层次的言语形式。
  可通过讲故事和演讲两种独白言语的训练,了解它们的一般特点、注意事项,结合进行运用态势语的训练,这类训练很有利于培养思维的条理性和连贯性。
  7、即兴小品训练
  即兴小品要求表演者按照规定的题目和要求,在规定的时间内,充分发挥自己的想象,不用或少用道具,通过言语和动作的表演,展现社会生活中的某个瞬间或片断,表达一个简单的主题。
  严格地说,小品应该是话剧艺术表演训练的一种形式,但由于它具有综合的特点,对训练思维的创造性、敏捷性、条理性、言语表达的准确性、形象性、流畅 性,以及应变力,乃至姿势的综合运用等等,都有很大的好处,所以我们要想英语口语表达能力更上一个层次,这种形式的训练也要加以采用。
  懂得了英语口语表达的规律,并不等于就有了一口流畅的英语表达口才,就好象读了介绍游泳的书并不等于一定会游泳一样,关键还是要在长期的时实践中持之 以恒地艰苦磨练。这种训练不同于我们平时常听常说的那种日常英语口语训练。日常的英语口语训练与之相比简单得多,所用的词汇量及话题所涉及的深度都是相当 有限的。而真正高层次的英语口语交际所需达到的流畅性、条理性、敏锐性和灵活性并不是常练一些日常用语就能达到的,其中用到的词汇量也因话题的深入和多样 而大大增加了。
  所以,要想真正地提高英语口语,说一口流利而又有水平的交际英语,得有对英语口语表达感兴趣作为前提,懂得以上的规律,重视运用以上的训练步骤,加上 长期的艰苦训练,才会有成效,才会达到目的。听力训练,当然,在训练过程中,听和说是无法截然分开的。
  因此,英语口语训练体系可按以下顺序安排:
  1、语音训练
  在学习英语语音知识的基础上加强语音训练,进行方音辨正练习。通过学习,打好英语语音知识,有一定的辨音能力,能用英语正确、清楚、响亮地表达。
  2、朗读朗诵训练
  进行呼吸、发声与共鸣训练,吐字纳音的训练,以及各种朗读朗诵技巧的训练,学会常用文体的朗读、朗诵,懂得在朗诵中恰当使用态势语


文章来源:http://blog.163.com/ccbobo_cat/blog/static/3209946220095109201252
posted @ 2009-06-10 09:20 C.B.K 阅读(85) | 评论 (0)编辑 收藏

[关键字]:java,design pattern,设计模式,《Java与模式》,Chain of Responsibility,责任链模式
[环境]:StarUML5.0 + JDK6
[作者]:Winty (wintys@gmail.com)
[正文]:

package pattern.chainofresponsibility;

/**
 * 责任链模式:Chain of Responsibility
 * @version 2009-5-9
 * @author Winty(wintys@gmail.com)
 */
public class ChainOfResponsibilityTest{
    public static void main(String[] args){
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        Handler handler3 = new ConcreteHandler3();

        //设置责任链
        handler3.setSuccessor(handler2);
        handler2.setSuccessor(handler1);

        //发送命令
        handler3.handleRequest();
    }
}

/**
 *抽象处理者
 */
abstract class Handler{
    protected Handler successor;

    public Handler getSuccessor(){
        return successor;
    }

    public void setSuccessor(Handler successor){
        this.successor = successor;
    }

    public abstract void handleRequest();
}

/**
 *具体处理者
 */
class ConcreteHandler1 extends Handler{
    public void handleRequest(){
        if(getSuccessor() != null){
            System.out.print("Request passed:from class Concrete1");
            System.out.println(" to class" + getSuccessor().getClass().getName());

            getSuccessor().handleRequest();
        }
        else{
            System.out.println("Request handled in ConcreteHandler1");
        }
    }
}

/**
 *具体处理者
 */
class ConcreteHandler2  extends Handler{
    public void handleRequest(){
        if(getSuccessor() != null){
            System.out.print("Request passed:from class Concrete2");
            System.out.println(" to class " + getSuccessor().getClass().getName());

            getSuccessor().handleRequest();
        }
        else{
            System.out.println("Request handled in ConcreteHandler2");
        }
    }
}

/**
 *具体处理者
 */
class ConcreteHandler3  extends Handler{
    public void handleRequest(){
        if(getSuccessor() != null){
            System.out.print("Request passed:from class Concrete3");
            System.out.println(" to class " + getSuccessor().getClass().getName());

            getSuccessor().handleRequest();
        }
        else{
            System.out.println("Request handled in ConcreteHandler3");
        }
    }
}

文章来源:http://blog.163.com/ccbobo_cat/blog/static/320994622009410264843
posted @ 2009-05-10 14:07 C.B.K 阅读(83) | 评论 (0)编辑 收藏
这么一个需求:同一台服务器上有两个应用,如
http://hostA:8080/serviceshttp://hostA:8080/admin
外部访问时,需要从不同的域名访问,如
http://services.host.comhttp://admin.host.com
一开始给他们这么一个比较简单的解决方案:
分别把services和admin两个应用,部署到不同的两个端口上,如
services -> http://hostA:8081/
admin -> http://hostA:8082/
接着在防火墙配两个公网IP,然后dns上把services.host.com和admin.host.com配置到这两个IP上。
当请求到达防火墙时,防火墙根据所访问的ip转发到hostA的对应端口上。
前 方用的防火墙是我们公司的Audemon 100,和公司的Audemon系统组的交流后得知,目前的防火墙版本不支持同时配置两个ip,要到六月底才能出版本支持。!@…%#%…%¥,晕倒,好 像这是很基本的功能来的吧,居然还不支持。没办法,此路不通。由于防火墙是不管域名的(因为域名资料是通过应用层传输的),那更别指望防火墙根据域名转发 了。
因此,我们只好提供了软件级的解决方案,让前方在Tomcat前加一个Apache 2.2,通过Apache的Virtual Host + AJP实现转发。
Apache的部分配置如下:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName host1.com
ProxyPass / ajp://host1.com:8009/
ProxyPassReverse / ajp://host1.com:8009/
</VirtualHost>
<VirtualHost *:80>
ServerName host2.com
ProxyPass / ajp://host2.com:8019/
ProxyPassReverse / ajp://host2.com:8019/
</VirtualHost>
Tomcat也需要配置AJP Connector,如host1.com的配置
<Connector port=”8009″ enableLookups=”false” redirectPort=”8443″ protocol=”AJP/1.3″ />
这个方案相对于防火墙的硬件方案,性能上要差一些,但还是不错的。
另 外还有一种方案是通过iptables的domain module来实现,但这个domain module好像是国内的某个高手写的,只更新到v0.02版本,并没有提交到iptables的标准里。虽然可以用而且性能比Apache的方案要高一 些,但是风险较大,而且配置麻烦(既要编译内核,又要配置iptables的rules),所以没有用这种方式。

文章来源:http://blog.163.com/ccbobo_cat/blog/static/320994622009326115641438
posted @ 2009-04-26 11:57 C.B.K 阅读(4196) | 评论 (0)编辑 收藏
随着访问量的不断提高,以及对响应速度的要求,进行负载均衡设置就显得非常必要了。公司的系统在最初设计的时候就已经考虑到了负载均衡的规划,www静态 服务器配置了两台,由于初期项目时间紧,并且访问量并不高,所以当时只用了一台,另一台在内网中,只是进行了同步,并为发挥出效用来。此次就是对负载均衡 的一个简单测试。
       先介绍一下apache mod_proxy_balancer的几个配置规则(从网上找的):
将Apache作为LoadBalance前置机分别有三种不同的部署方式,分别是:

1 )轮询均衡策略的配置

进入Apache的conf目录,打开httpd.conf文件,在文件的末尾加入:
ProxyPass / balancer://proxy/         #注意这里以"/"结尾
<Proxy balancer://proxy> 
       BalancerMember http://192.168.6.37:6888/ 
       BalancerMember http://192.168.6.38:6888/
</Proxy> 
      我们来观察上述的参数“ProxyPass / balancer://proxy/”,其中,“ProxyPass”是配置虚拟服务器的命令,“/”代表发送Web请求的URL前缀,如:http://myserver/或者http://myserver/aaa,这些URL都将符合上述过滤条件;“balancer://proxy/”表示要配置负载均衡,proxy代表负载均衡名;BalancerMember 及其后面的URL表示要配置的后台服务器,其中URL为后台服务器请求时的URL。以上面的配置为例,实现负载均衡的原理如下: 
      假设Apache接收到http://localhost/aaa请求,由于该请求满足ProxyPass条件(其URL前缀为“/”),该请求会被分发到后台某一个BalancerMember,譬如,该请求可能会转发到 http://192.168.6.37:6888/aaa进行处理。当第二个满足条件的URL请求过来时,该请求可能会被分发到另外一台BalancerMember,譬如,可能会转发到http://192.168.6.38:6888/。如此循环反复,便实现了负载均衡的机制。

2) 按权重分配均衡策略的配置

ProxyPass / balancer://proxy/         #注意这里以"/"结尾

<Proxy balancer://proxy> 
        BalancerMember http://192.168.6.37:6888/  loadfactor=3 
        BalancerMember http://192.168.6.38:6888/  loadfactor=1
</Proxy> 
      参数”loadfactor”表示后台服务器负载到由Apache发送请求的权值,该值默认为1,可以将该值设置为1到100之间的任何值。以上面的配置 为例,介绍如何实现按权重分配的负载均衡,现假设Apache收到http://myserver/aaa 4次这样的请求,该请求分别被负载到后台服务器,则有3次连续的这样请求被负载到BalancerMember为http://192.168.6.37:6888的服务器,有1次这样的请求被负载BalancerMember为http://192.168.6.38:6888后台服务器。实现了按照权重连续分配的均衡策略。

3) 权重请求响应负载均衡策略的配置

ProxyPass / balancer://proxy/ lbmethod=bytraffic  #注意这里以"/"结尾

<Proxy balancer://proxy> 
         BalancerMember http://192.168.6.37:6888/  loadfactor=3 
         BalancerMember http://192.168.6.38:6888/  loadfactor=1 
 </Proxy> 
       参数“lbmethod=bytraffic”表示后台服务器负载请求和响应的字节数,处理字节数的多少是以权值的方式来表示的。 “loadfactor”表示后台服务器处理负载请求和响应字节数的权值,该值默认为1,可以将该值设置在1到100的任何值。根据以上配置是这么进行均 衡负载的,假设Apache接收到http://myserver/aaa请求,将请求转发给后台服务器,如果BalancerMember为http://192.168.6.37:6888后台服务器负载到这个请求,那么它处理请求和响应的字节数是BalancerMember为http://192.168.6.38:6888 服务器的3倍(回想(2)均衡配置,(2)是以请求数作为权重负载均衡的,(3)是以流量为权重负载均衡的,这是最大的区别)。

看明白了没有,根据不同的需要,可以按这三种方式进行配置。我按照第三种配置的,感觉上这种对于负载的均衡更全面合理。我的配置很简单,如下:
先配置均衡器:
<Proxy balancer://proxy>
       BalancerMember ajp://127.0.0.1:8009/  loadfactor=1
       BalancerMember http://192.168.10.6:8083/  loadfactor=1
</Proxy>
其中http://192.168.10.6:8083实际上是另外一个端口启动的apache,为了测试,它就简单的直接转发所有请求到tomcat。
对于上次的VirtualHost进行以下的修改即可:
<VirtualHost *:80>
        ServerName www.test.com
        DocumentRoot /www
        DirectoryIndex index.html index.jsp
        <Directory "/www">
            Options Indexes FollowSymLinks
            AllowOverride None
            Order allow,deny
            Allow from all
        </Directory>
        <Directory "/control">
            Options Indexes FollowSymLinks
            AllowOverride None
            Order allow,deny
            Allow from all
        </Directory>
        ProxyPass /nxt/images/ !
        ProxyPass /nxt/js/ !
        ProxyPass /nxt/css/ !
        #ProxyPass / ajp://127.0.0.1:8009/
        #ProxyPassReverse / ajp://127.0.0.1:8009/
        ProxyPass / balancer://proxy/
        ProxyPassReverse / balancer://proxy/
</VirtualHost>
注释掉之前的ajp转发,而配置成通过balancer去处理。
通过观察access log,的确有部分请求发送到了8083端口的apache上,而有部分是直接ajp转发到tomcat上了。对于更多的负载均衡的参数检测,待空了再做。


文章来源:http://blog.163.com/ccbobo_cat/blog/static/32099462200932611555639
posted @ 2009-04-26 11:56 C.B.K 阅读(146) | 评论 (0)编辑 收藏

一、集群和负载均衡的概念

(一)集群的概念

  集群(Cluster)是由两台或多台节点机(服务器)构成的一种松散耦合的计算节点集合,为用 户提供网络服务或应用程序(包括数据库、Web服务和文件服务等)的单一客户视图,同时提供接近容错机的故障恢复能力。集群系统一般通过两台或多台节点服 务器系统通过相应的硬件及软件互连,每个群集节点都是运行其自己进程的独立服务器。这些进程可以彼此通信,对网络客户机来说就像是形成了一个单一系统,协 同起来向用户提供应用程序、系统资源和数据。除了作为单一系统提供服务,集群系统还具有恢复服务器级故障的能力。集群系统还可通过在集群中继续增加服务器 的方式,从内部增加服务器的处理能力,并通过系统级的冗余提供固有的可靠性和可用性。
(二)集群的分类
1、高性能计算科学集群:
   以解决复杂的科学计算问题为目的的IA集群系统。是并行计算的基础,它可以不使用专门的由十至上万个独立处理器组成的并行超级计算机,而是采用通过高速 连接来链接的一组1/2/4 CPU的IA服务器,并且在公共消息传递层上进行通信以运行并行应用程序。这样的计算集群,其处理能力与真正超级并行机相等,并且具有优良的性价比。
2、负载均衡集群:
   负载均衡集群为企业需求提供更实用的系统。该系统使各节点的负载流量可以在服务器集群中尽可能平均合理地分摊处理。该负载需要均衡计算的应用程序处理端 口负载或网络流量负载。这样的系统非常适合于运行同一组应用程序的大量用户。每个节点都可以处理一部分负载,并且可以在节点之间动态分配负载,以实现平 衡。对于网络流量也如此。通常,网络服务器应用程序接受了大量入网流量,无法迅速处理,这就需要将流量发送给在其它节点。负载均衡算法还可以根据每个节点 不同的可用资源或网络的特殊环境来进行优化。
3、高可用性集群:
  为保证集群整体服务的高可用,考虑计算硬件和软件的容错性。如果高可用性群集中的某个节点发生了故障,那么将由另外的节点代替它。整个系统环境对于用户是一致的。

  实际应用的集群系统中,这三种基本类型经常会发生混合与交杂。

(三)典型集群
科学计算集群:
1、Beowulf
当谈到 Linux 集群时,许多人的第一反映是 Beowulf。那是最著名的 Linux科学软件集群系统。实际上,它是一组适用于在 Linux 内核上运行的公共软件包的通称。其中包括流行的软件消息传递 API,如“消息传送接口”(MPI) 或“并行虚拟机”(PVM),对 Linux 内核的修改,以允许结合几个以太网接口、高性能网络驱动器,对虚拟内存管理器的更改,以及分布式进程间通信 (DIPC) 服务。公共全局进程标识空间允许使用 DIPC 机制从任何节点访问任何进程。
2、MOSIX
Beowulf类似于给系统安装的一个支持 集群的外挂软件,提供了应用级的集群能力。而MOSIX是彻底修改Linux的内核,从系统级提供了集群能力,它对应用而言是完全透明的,原有的应用程 序,可以不经改动,就能正常运行在MOSIX系统之上。集群中的任何节点都可以自由地加入和移除,来接替其它节点的工作,或是扩充系统。MOSIX 使用自适应进程负载均衡和内存引导算法使整体性能最大化。应用程序进程可以在节点之间实现迁移,以利用最好的资源,这类似于对称多处理器系统可以在各个处 理器之间切换应用程序。由于MOSIX通过修改内核来实现集群功能,所以存在兼容性问题,部分系统级应用程序将无法正常运行。

负载均衡/高可用性集群
3、LVS(Linux Virtual Server)
这是一个由国人主持的项目。
它是一个负载均衡/高可用性集群,主要针对大业务量的网络应用(如新闻服务、网上银行、电子商务等)。
LVS 是建立在一个主控服务器(通常为双机)(director)及若干真实服务器(real-server)所组成的集群之上。real-server负责实 际提供服务,主控服务器根据指定的调度算法对real-server进行控制。而集群的结构对于用户来说是透明的,客户端只与单个的IP(集群系统的虚拟 IP)进行通信,也就是说从客户端的视角来看,这里只存在单个服务器。
N54537Real-server可以提供众多服务,如ftp, http, dns, telnet, nntp, smtp 等。主控服务器负责对Real-Server进行控制。客户端在向LVS发出服务请求时,Director会通过特定的调度算法来指定由某个Real- Server来应答请求,而客户端只与Load Balancer的IP(即虚拟IP,VIP)进行通信。

其他集群:
现在集群系统可谓五花八门,绝大部分的OS开发商,服务器开发商都提供了系统级的 集群产品,最典型的是各类双机系统,还有各类科研院校提供的集群系统。以及各类软件开发商提供的应用级别的集群系统,如数据库集 群,Application Server 集群,Web Server集群,邮件集群等等。

(四)负载均衡

1、概念

    由于目前现有网络的各个核心部分随着业务量的提高,访问量和数据流量的快速增长,其处理能力和计算强度也相应地增大,使得单一的服务器设备根本无法承担。 在此情况下,如果扔掉现有设备去做大量的硬件升级,这样将造成现有资源的浪费,而且如果再面临下一次业务量的提升时,这又将导致再一次硬件升级的高额成本 投入,甚至性能再卓越的设备也不能满足当前业务量增长的需求。

针对此情况而衍生出来的一种廉价有效透明的方法以扩展现有网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性的技术就是负载均衡(Load Balance)。

2、特点和分类

     负载均衡(Server Load Balance)一般用于提高服务器的整体处理能力,并提高可靠性,可用性,可维护性,最终目的是加快服务器的响应速度,从而提高用户的体验度。  

     负载均衡从结构上分为本地负载均衡(Local Server Load Balance)和地域负载均衡(Global Server Load Balance)(全局负载均衡),一是指对本地的服务器群做负载均衡,另一是指对分别放置在不同的地理位置、有不同的网络及服务器群之间作负载均衡。   

地域负载均衡有以下的特点:

(1)解决网络拥塞问题,服务就近提供,实现地理位置无关性

(2)对用户提供更好的访问质量

(3)提高服务器响应速度

(4)提高服务器及其他资源的利用效率

(5)避免了数据中心单点失效

3、负载均衡技术主要应用

(1)DNS负载均衡 最早的负载均衡技术是通过DNS来实现的,在DNS中为多个地址配置同一个名字,因而查询这个名字的客户机将得到其中一个地址,从而使得不同的客户访问不 同的服务器,达到负载均衡的目的。DNS负载均衡是一种简单而有效的方法,但是它不能区分服务器的差异,也不能反映服务器的当前运行状态。

(2)代理服务器负载均衡 使用代理服务器,可以将请求转发给内部的服务器,使用这种加速模式显然可以提升静态网页的访问速度。然而,也可以考虑这样一种技术,使用代理服务器将请求均匀转发给多台服务器,从而达到负载均衡的目的。

(3)地址转换网关负载均衡 支持负载均衡的地址转换网关,可以将一个外部IP地址映射为多个内部IP地址,对每次TCP连接请求动态使用其中一个内部地址,达到负载均衡的目的。

(4)协议内部支持负载均衡 除了这三种负载均衡方式之外,有的协议内部支持与负载均衡相关的功能,例如HTTP协议中的重定向能力等,HTTP运行于TCP连接的最高层。

(5)NAT 负载均衡 NAT(Network Address Translation 网络地址转换)简单地说就是将一个IP地址转换为另一个IP地址,一般用于未经注册的内部地址与合法的、已获注册的Internet IP地址间进行转换。适用于解决Internet IP地址紧张、不想让网络外部知道内部网络结构等的场合下。

(6)反向代理负载均 衡 普通代理方式是代理内部网络用户访问internet上服务器的连接请求,客户端必须指定代理服务器,并将本来要直接发送到internet上服务器的连 接请求发送给代理服务器处理。反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。反向代理负载均衡技术是把将来自internet上的连接请求以反向代理的 方式动态地转发给内部网络上的多台服务器进行处理,从而达到负载均衡的目的。

(7)混合型负载均衡 在有些大型网络,由于多个服务器群内硬件设备、各自的规模、提供的服务等的差异,我们可以考虑给每个服务器群采用最合适的负载均衡方式,然后又在这多个服 务器群间再一次负载均衡或群集起来以一个整体向外界提供服务(即把这多个服务器群当做一个新的服务器群),从而达到最佳的性能。我们将这种方式称之为混合 型负载均衡。此种方式有时也用于单台均衡设备的性能不能满足大量连接请求的情况下。

二、搭建集群和实现负载平衡

(一)前期准备

我的系统用的是windowsXP专业版,我要做的是,用一个apache和多个(这里以两个作为示例)tomcat,通过jk方式,构造一个集群。以下是要首先准备的东西:

1、jdk,我用的版本是jdk1.5.0_06,下载地址是http://192.18.108.216/ECom/EComTicketServlet/BEGIND597A309654D73D910E051D73D539D5F/-2147483648/2438196255/1/852050/851882/2438196255/2ts+/westCoastFSEND/jdk-1.5.0_13-oth-JPR/jdk-1.5.0_13-oth-JPR:3/jdk-1_5_0_13-windows-i586-p.exe

2、apache,我用的版本是2.2.4,下载地址是http://apache.justdn.org/httpd/binaries/win32/apache_2.2.4-win32-x86-openssl-0.9.8d.msi

3、tomcat,我用的版本是5.5的解压版本,这里要注意:不能用安装的版本,因为一台机器上装两个一样的tomcat,是会出错误的。下载地址是http://apache.mirror.phpchina.com/tomcat/tomcat-5/v5.5.25/bin/apache-tomcat-5.5.25.zip

4、jk,这个jk的版本,本来有两个的,但是版本2已经被废弃掉了,目前可用的jk版本是1.2.25。每个apache的版本,都会有一个特定的jk与之对应,所以这里要用的jk也必须是为apache-2.2.4开发的那个才行。它的下载地址是http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/win32/jk-1.2.25/mod_jk-apache-2.2.4.so

有了这四样东西,我们就可以开始做集群了。

(二)安装

1、相信需要看这篇文章的人,JDK的安装一定不会陌生,这里不在赘述。只是需要提醒一下:环境变量别忘记配置了。

2、安装apache也没有什么难度,就是在安装过程中要配置域名、网址和管理员邮箱之类的信息,这 个信息完全可以按照提示,然后修改下填入即可,之后想修改的话直接到配置文件中改就行了。除了这个地方,还要保证机器上的80端口没有被其他程序占用。至 于安装路径,完全取决于个人爱好。其他的默认就行了。安装成功后,系统右下角的托盘区会有个图标,我们可以通过这个启动apache,如果那个小红点变成 绿色,说明服务已经正常启动了(如果服务没有启动起来,说明安装过程中的配置有错误,建议卸载后重装)。如果按照默认,端口是80的话,那打开浏览器,输 入:http://localhost/ ,应该可以看到 " It works “的字样。这样就可以进入下一步了。

3、解压缩tomcat,记得要做两份。这里不妨将两个tomcat命名为:tomcat- 5.5.25_1和tomcat-5.5.25_2,其实这两个文件夹中的东西是完全一样的。但是我为了在同一台机器上做集群,那就要保证两个 tomcat运行起来不会在端口上起冲突。进入tomcat-5.5.25_1/conf目录,用文本编辑器打开并修改server.xml,将该 tomcat的默认8080端口改为8088(其实没必要改,我改这个是因为我机器上还有其他tomcat占用着8080端口)。然后进入tomcat- 5.5.25_2/conf目录,同样将8080修改掉,至于改成多少没多大关系,只要不占用其他程序的端口,应该不会出什么问题。这样,tomcat就 算安装好了。

4、jk这东西是一个连接模块,不用安装,直接将mod_jk-apache-2.2.4.so这个文件拷贝到apache安装目录下的modules文件夹下面就行了。

这样,安装完成,下面开始配置。

(三)配置

这个地方才是搭建集群的关键所在,我也会尽我的可能写的详细点。

1、配置tomcat

为防止冲突,进入第二个tomcat主目录,然后进入conf目录,打开server.xml修改配 置。主要是修改端口,我这里把所有的端口信息,都在原有基础上加1000,即原端口是8009,我改为9009。当然,你不必和我一样,只要保证不冲突就 OK!这些配置在apache的配置中可能会用到。

2、配置apache

(1)进入apache的主目录,然后进入conf文件夹,用文本编辑器打开httpd.conf,在该文件末尾加上如下几行:

### 加载 mod_jk 模块
LoadModule jk_module modules/mod_jk-apache-2.2.4.so

### 配置 mod_jk
JkWorkersFile conf/workers.properties           #加载集群中的workers
JkMountFile conf/uriworkermap.properties    #加载workers的请求处理分配文件
JkLogFile logs/mod_jk.log                                #指定jk的日志输出文件
JkLogLevel warn                                                  #指定日志级别

(2)不要改变目录,新建一个文件:workers.properties,该文件用来配置web容器的信息。该文件的内容如下:

# worker列表
worker.list=controller, status

#第一个server的配置,server名为s1
#ajp13 端口号,在tomcat下server.xml配置,默认8009
worker.s1.port=8009
#tomcat的主机地址,如不为本机,请填写ip地址
worker.s1.host=localhost
worker.s1.type=ajp13
#server的加权比重,值越高,分得的请求越多
worker.s1.lbfactor=1

#第二个server的配置,server名为s2
worker.s2.port=9009
worker.s2.host=localhost
worker.s2.type=ajp13
worker.s2.lbfactor=1

#server名为controller,用于负载均衡
worker.controller.type=lb
worker.retries=3   #重试次数
#指定分担请求的server列表,用逗号分隔
worker.controller.balanced_workers=s1,s2
#设置用于负载均衡的server的session可否共享 有不少文章说设置为1是可以的,但是我是设置为0才可以的
worker.controller.sticky_session=0
#worker.controller.sticky_session_force=1

worker.status.type=status

(3)不要改变目录,新建一个文件:uriworkermap.properties,文件内容如下:

/*=controller                         #所有请求都由controller这个server处理
/jkstatus=status                   #所有包含jkstatus请求的都由status这个server处理

!/*.gif=controller                   #所有以.gif结尾的请求都不由controller这个server处理,以下几个都是一样的意思
!/*.jpg=controller
!/*.png=controller
!/*.css=controller
!/*.js=controller
!/*.htm=controller
!/*.html=controller

这里的"!”类似于java中的"!”,是“非”的意思。

这样,apache一块就配置好了。

3、再修改tomcat配置:这里两个tomcat都要配置。

仍然是打开第一步中的那个server.xml文件,找到<Engine name="Catalina" defaultHost="localhost">这一行,在里面加上一句:jvmRoute="s1",即把该句改为:<Engine name="Catalina" defaultHost="localhost" jvmRoute="s1">。这里的s1就是第二步中配置的用于负载均衡的server的名称。如果该tomcat的端口是第二步中s1用的端 口,那这里就写s1,第二个tomcat就应该是s2了。

这样,配置就完成了。

(四)运行

进入两个tomcat的bin目录,执行两个tomcat的startup.bat启动这两个 tomcat,然后将apache重新启动后,运行起来看看效果吧。如果不出意外,两个tomcat的窗口应该是你一次我一次的打印日志信息了,而且此时 session也是共享了的。

到这里,集群搭建好了,负载均衡也实现了。


文章来源:http://blog.163.com/ccbobo_cat/blog/static/32099462200932611544216
posted @ 2009-04-26 11:54 C.B.K 阅读(189) | 评论 (0)编辑 收藏
附录B SQL*PLUS
Sql*plus 中使用绑定变量:
sql> variable x number;
sql> exec :x := 7788;
sql> SELECT empno,ename from scott.emp where empno=:x;
SQL*PLUS 是Oracle提供的一个工具程序,它不仅可以用于测试,运行SQL语句和PL/SQL块,而且还可以用于管理Oracle数据库,
1.启动sql*plus
为了使用sql*plus,必须首先要启动sql*plus。Oracle不仅提供了命令行和图形界面的sql*plus,而且还可以在web浏览器中
运行.
(1)在命令运行sql*plus
在命令行运行sql*plus是使用sqlplus命令来完成的,该命令适用于任何操作系统平台,
语法如下:
   sqlplus [username]/[password][@server]
如上所示:username用于指定数据库用户名,password用于指定用户口令,server则用于指定主机字符串(网络服务名).
当连接到本地数据时,不需要提供网络服务名,如果要连接到远程数据库,则必须要使用网络服务名.
(2)在windows环境中运行sql*plus
如果在windows环境中安装了oralce数据库产品,那么可以在窗口环境中运行sql*plus
具体方法: "开始->程序->oracle-oradb10g_home1->application development->sql*plus"
2.连接命令
(1)conn[ect]
   该命令用于连接到数据库。注意,使用该命令建立新会话时,会自动断开先前会话,示例如下:
   sql>conn scott/yhai1981@demo
(2)disc[onnect]
   该命令用于断开已经存在的数据库连接。注:该命令只是断开连接会话,而不会退出sql*plus,示例如下:
   sql>disc
(3)passw[ord]
   该命令用于修改用户的口令。注,任何用户都可以使用该命令修改其自身口令,但如果要修改其他用户的口令时,
则必须以DBA身份(sys和system)登录,在sql*plus中,当修改用户口令时,可以使用该命令取代sql命令alter user,
   示例如下:
sql>passw
更改scott的口令
旧口令:******
新口令:******
重新键入新口令:******
口令已更改
sql>
(4)exit
该命令用于退出 sql*plus,另外你也可以使用quit命令退出sql*plus.使用该命令不仅会断开连接,而且也会退出sql*plus
注:默认情况下,当执行该命令时会自动提交事务。
3,编辑命令
(1)l[ist]
   该命令用于列出sql缓冲区的内容,使用该命令可以列出sql缓冲某行,某几行或所有行的内容。在显示结果中,数据字为具体
的行号,而"*"则表示当前行。
示例一:列出sql缓冲区所有内容
     sql>l
示例二:列出sql缓冲区首行内容:
     sql>l1
(2)a[ppend]
   该命令用于在sql缓冲区的当前行尾部添加内容。注:该命令将内容追加到标记为"*"的行的尾部,示例如下:
   sql>l
     1 select empno,ename,sal,hiredate,comm,deptno
     2 from emp
     3* where deptno=10
   sql>a and job='CLERK'
   sql>l
   SQL> list
    1 select empno,ename,sal,hiredate,comm,deptno
    2 from emp
    3* where deptno=10 and job='CLERK'
(3)c[hange]
   该命令用于修改sql缓冲区的内容。如果在编写sql语句时写错了某个词,那么使用该命令可以进行修改,
    sql>select ename from temp where deptno=10;
    SQL> c /temp/emp
      1* select ename from emp where deptno=10
(4)del
   该命令用于删除sql缓冲区中内容,使用它可以删除某行,某几行或所有行,在默认情况下,当直接执行
del时,只删除当前行的内容,示例如下:
   SQL> l
   1 select ename
   2 from emp
   3* where deptno=20
   sql>del
   SQL> l
   1 select ename
   2* from emp
   如果一次要删除多行,则指定起始行号和终止行号,例如"del 3 5"
(5)i[nput]
   该命令用于在sql缓冲区的当前行后新增加一行。示例如下:
   SQL> l
    1 select ename
    2* from emp
   sql>i where deptno=30
   如果要在首行前增加内容,则使用"0文本"
   sql>0 create table temp as
   SQL> l
1 create table temp as
2 select ename
3 from emp
4* where deptno=30
(6) n
该数值用于定位sql缓冲区的当前行,示例如下:
(7)edi[t]
   该命令用于编辑sql缓冲区的内容。当运行该命令时,在windows平台中会自动启动"记事本",以编辑sql缓冲区
(8)run和/
   run的/命令都可以用于运行sql缓冲区中的sql语句。注:当使用run命令时,还会列出sql缓冲区内容,eg:
   SQL> run
   1* select ename from emp where deptno=20
   4.文件操纵命令
   (1)save
   该命令用于将当前sql缓冲区的内容保存到sql脚本中。当执行该命令时,默认选项为create,即建立新文件。
   eg:
   SQL> save c:\a.sql create
   已创建 file c:\a.sql
    当执行命令之后,就会建立新脚本文件a.sql,并将sql缓冲区内容存放到该文件中。如果sql已经存在,使用
   replace选项可以替撚已存在的sql脚本,如果要给已存在的sql脚本追加内容,可以使用append选项。
   (2)get
    该命令与save命令作用恰好相反,用于将sql脚本中的所有内容装载到sql缓冲区中。
    eg:
    SQL> get c:\a.sql
    1* select ename from emp where deptno=20
   (3)start和@
    start和@命令用于运行sql脚本文件。注:当运行sql脚本文件时,应该指定文件路径.eg:
    SQL> @c:\a.sql
    ENAME
    ----------
    SMITH
    JONES
    SCOTT
    ADAMS
    FORD
   (4)@@
    该命令与@命令类似,也可以运行脚本文件,但主要作用是在脚本文件中嵌套调用其它的脚本文件。当使用该命令
    嵌套脚本文件时,可在调用文件所在目录下查找相应文件名。
   (5)ed[it]
    该命令不仅可用于编辑sql缓冲区内容,也可以用于编辑sql脚本文件。当运行该命令时,会启动默认的系统编辑
    器来编辑sql脚本。运行方法为:
    sql>edit c:/a.sql
   (6)spool
    该命令用于将sql*plus屏幕内容存放到文本文件中。执行该命令时,应首先建立假脱机文件,并将随后sql*plus
    屏幕的所有内容全部存放到该文件中,最后使用spool off命令关闭假脱机文件。eg:
    sql>spool c:\a.sql
    5.格式命令
     sql*plus不仅可以用于执行sql语句、pl/sql块,而且还可以根据select结果生成报表。使用sql*plus的格式命令
    可以控制报表的显示格式,例如使用column命令可以控制列的显示格式,使用ttitle命令可以指定页标题;使用
    btitle命令可以指定页脚注。
    (1)col[umn]
     该命令用于控制列的显示格式。column命令包含有四个选项,其中clear选项用于清除已定义列的显示格式:
     heading选项用于指定列的显示标题;justify选项用于指定列标题的对齐格式(left,center,right);format选项用于
     指定列的显示格式,其中格式模型包含以下一些元素。
     An:设置char,varchar2类型列的显示宽度;
     9: 在number类型列上禁止显示前导0;
     0: 在number类型列上强制显示前导0;
     $: 在number类型列前显示美元符号;
     L: 在number类型列前显示本地货币符号;
     .: 指定number类型列的小数点位置;
     ,: 指定number类型列的千分隔符;
    eg1:使用column设置列显示格式
     sql>col ename heading 'name' format a10
     sql>col sal heading 'sal' format L99999.99
     sql>select ename,sal,hiredate from emp
     sql>where empno=7788;
     name                       sal HIREDATE
     ---------- ------------------- -------------------
     SCOTT                ¥3000.00 04/19/1987 00:00:00
     sql>col ename clear
     sql>col sal clear
     sql>select ename,sal,hiredate from emp
     sql>where empno=7788;
     (2)title
     该命令用于指定页标题,页标题会自动显示在页的中央。如果页标题由多个词组成,则用单引号引住。如果要将页
    标题分布在多行显示,则用"|"分开不同单词。如果不希望显示页标题,则使用"ttitle off"命令,禁止显示,eg:
SQL> set linesize 40
SQL> ttitle 'employee report'
SQL> select ename,sal,hiredate from emp where empno=7788;

星期二 5月 20                第    1
            employee report

ENAME             SAL
---------- ----------
HIREDATE
-------------------
SCOTT            3000
04/19/1987 00:00:00
   (3)btitle
该命令用于指定页脚注,页脚注会自动显示在页的中央。如果页脚注由多个词组成,则用单引号引注。如果要将页脚注
分布在多行显示,则用"|"分开不同单词。如果不希望显示页脚注,则使用"btitle off"命令,禁止显示。eg:
   SQL> btitle 'page end'
   SQL> select ename,sal,hiredate from emp where empno=7788
ENAME             SAL
---------- ----------
HIREDATE
-------------------
SCOTT            3000
04/19/1987 00:00:00
         page end
(4)break
该命令用于禁止显示重复行,并将显示结果分隔为几个部分,以表现更友好的显示结果,通常应该在order by 的排序列上
使用该命令。eg:
SQL> set pagesize 40
SQL> break on deptno skip 1
SQL> select deptno,ename,sal from emp order by deptno
2 ;

    DEPTNO ENAME             SAL
---------- ---------- ----------
        10 CLARK            2450
           KING             5000
           MILLER           1300

        20 JONES            2975
           FORD             3000
           ADAMS            1100
           SMITH             800
           SCOTT            3000

        30 WARD             1250
           TURNER           1500
           ALLEN            1600
           JAMES             950
           BLAKE            2850
           MARTIN           1250
   6.交互式命令
    如果经常要执行某些sql语句和sql*plus命令,可以将这些语句和命令存放到sql脚本中。通过使用sql脚本,
   一方面可以降低命令输入量,另一方面可以避免用户的输入错误。为了使得sql脚本可以根据不同输入获得
   不同结果,需要在sql脚本中包含交互式命令。通过使用交互式命令,可以在sql*plus中定义变量,并且在运行
   sql脚本时可以为这些变量动态输入数据。下面介绍sql*plus的交互命令,以及引用变量所使用的标号。
(1)&
    引用替代变量(substitution variable)时,必须要带有该标号。如果替代变量已经定义,则会直接使用其数据,
    如果替代变量没有定义,则会临时定义替代变量(该替代变量只在当前语句中起作用),并需要为其输入数据。
    注:如果替代变量为数字列则提供数据,则可以直接引用;如果替代变量为字符类型列或日期类型列提供数据,
    则必须要用单引号引注。eg:
SQL> select ename,sal from emp where deptno=&no and job='&job';
输入 no 的值: 20
输入 job 的值: CLERK
原值    1: select ename,sal from emp where deptno=&no and job='&job'
新值    1: select ename,sal from emp where deptno=20 and job='CLERK'
   (2)&&
   该标号类似于单个&标号。但需要注意,&标号所定义的替代变量只在当前语句中起作用;而&&标号所定义的变量
会在当前sql*plus环境中一直生效。eg:
SQL> select ename,sal from emp where deptno=&&no and job='&&job' --定义了no变量
输入 no 的值: 20
输入 job 的值: CLERK
原值    1: select ename,sal from emp where deptno=&&no and job='&&job'
新值    1: select ename,sal from emp where deptno=20 and job='CLERK'
SQL> select ename,sal from emp where deptno=&no;           
原值    1: select ename,sal from emp where deptno=&no             --直接引用no变量
新值    1: select ename,sal from emp where deptno=20
ENAME             SAL
---------- ----------
SMITH             800
JONES            2975
SCOTT            3000
ADAMS            1100
FORD             3000
如例所示,当第一次引用no变量时,使用&&标号需要为其输入数据;当第二次引用no变量时,
使用&标号直接引用其原有值,而不需要输入数据。
(3)define
该命令用于定义类型为char的替代变量,而且该命令的定义的替代变量只在当前sql*plus环境中起作用。
当使用该命令定义变量时,如果变量值包含空格或区分大小写,则用引号引注。另外,使用"define变量名"可以检查变量
是否已经定义。eg:
sql>set verify off
sql>define title=CLERK
sql>select ename,sal from where job='&title';
(4)accept
该命令可以用于定义char,number和date类型的替代变量。与define命令相比,accept命令更加灵活。当使用该命令定义替代
变量时,还可以指定变量输入提示、变量输入格式、隐藏输入内容。
eg1:指定变量输入提示
SQL> accept title prompt '请输入岗位:'
请输入岗位:CLERK
SQL> select ename,sal from emp where job='&title';
原值    1: select ename,sal from emp where job='&title'
新值    1: select ename,sal from emp where job='CLERK'

ENAME             SAL
---------- ----------
SMITH             800
ADAMS            1100
JAMES             950
MILLER           1300
eg2:隐藏用户输入
sql>accept pwd hide
(5)undefine
该命令用于清除替代变量的定义。eg:
sql>undefine pwd
SQL> disc
从 Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options 断开
SQL> conn scott/&pwd
输入 pwd 的值: yhai1981
已连接
(6)prompt的pause
prompt命令用于输出提示信息,而pause命令则用于暂停脚本执行。在sql脚本中结合使用这两条命令,可以控制sql脚本
的暂停的执行。假定在a.sql脚本中包含以下命令:
prompt '按<Return>键继续'
pause
当运行该sql脚本时,会暂停执行,eg:
sql>@c:\a.sql
'按<Return>键继续'
(7)variable
该命令用于在sql*plus中定义绑定变量。当在sql语句或pl/sql块中引用绑定变量时,必须要在绑定变量前加冒号(:);
当直接给绑定变量赋值时,需要使用execute命令(类似于调用存储过程).示例如下:
sql>var no number
sql>exec :no:=7788
sql>select ename from emp where empno=:no;
ename
------------------
scott
(8)print
该命令用于输出绑定变量结果,eg:
SQL> print no

        NO
----------
      7788
7.显示和设置环境变量
使用sql*plus的环境变量可以控制其运行环境,例如设置行显示宽度,设置每页显示的行数、
设置自动提交标记、设置自动跟踪等等。使用show命令可以显示当前sql*plus的环境变量设置
:使用set命令可以修改当前sql*plus的环境变量设置。下面介绍常用的sql*plus环境变量。
(1)显示所有环境变量
为了显示sql*plus的所有环境变量,必须要使用show all命令。示例如下:
SQL> show all
appinfo 为 OFF 并且已设置为 "SQL*Plus"
arraysize 15
autocommit OFF
autoprint OFF
autorecovery OFF
autotrace OFF
blockterminator "." (hex 2e)
btitle OFF 为下一条 SELECT 语句的前几个字符
cmdsep OFF
colsep " "
compatibility version NATIVE
concat "." (hex 2e)
copycommit 0
COPYTYPECHECK 为 ON
define "&" (hex 26)
describe DEPTH 1 LINENUM OFF INDENT ON
echo OFF
editfile "afiedt.buf"
embedded OFF
escape OFF
用于 6 或更多行的 FEEDBACK ON
flagger OFF
flush ON
heading ON
headsep "|" (hex 7c)
instance "local"
linesize 80
lno 4
loboffset 1
logsource ""
long 80
longchunksize 80
markup HTML OFF HEAD "<style type='text/css'> body {font:10pt Arial,Helvetica,sans-serif; color:black; background:White;} p {font:10pt Arial,Helvetica,sans-serif; color:black; background:White;} table,tr,td {font:10pt Arial,Helvetica,sans-serif; color:Black; background:#f7f7e7; padding:0px 0px 0px 0px; margin:0px 0px 0px 0px;} th {font:bold 10pt Arial,Helvetica,sans-serif; color:#336699; background:#cccc99; padding:0px 0px 0px 0px;} h1 {font:16pt Arial,Helvetica,Geneva,sans-serif; color:#336699; background-color:White; border-bottom:1px solid #cccc99; margin-top:0pt; margin-bottom:0pt; padding:0px 0px 0px 0px;} h2 {font:bold 10pt Arial,Helvetica,Geneva,sans-serif; color:#336699; background-color:White; margin-top:4pt; margin-bottom:0pt;} a {font:9pt Arial,Helvetica,sans-serif; color:#663300; background:#ffffff; margin-top:0pt; margin-bottom:0pt; vertical-align:top;}</style><title>SQL*Plus Report</title>" BODY "" TABLE "border='1' width='90%' align='center' summary='Script output'" SPOOL OFF ENTMAP ON PREFORMAT OFF
newpage 1
null ""
numformat ""
numwidth 10
pagesize 14
PAUSE 为 OFF
pno 1
recsep WRAP
recsepchar " " (hex 20)
release 1002000100
repfooter OFF 为 NULL
repheader OFF 为 NULL
serveroutput OFF
shiftinout INVISIBLE
showmode OFF
spool ON
sqlblanklines OFF
sqlcase MIXED
sqlcode 0
sqlcontinue "> "
sqlnumber ON
sqlpluscompatibility 10.2.0
sqlprefix "#" (hex 23)
sqlprompt "SQL> "
sqlterminator ";" (hex 3b)
suffix "sql"
tab ON
termout ON
timing OFF
trimout ON
trimspool OFF
ttitle OFF 为下一条 SELECT 语句的前几个字符
underline "-" (hex 2d)
USER 为 "SCOTT"
verify ON
wrap : 将换至下一行
SQL> spool off

(2)arraysize
该环境变量用于指定数组提取尺寸,其默认值为15.该值越大,网络开销将会越低,但占用内存会增加。假定使用默认值,
如果查询返回行数为50行,则需要通过网络传送4将数据;如果设置为25,则网络传送次数只有两次。eg:

SQL> show arraysize
arraysize 15
SQL> set arraysize 25
(3)autocommit
该环境变量用于设置是否自动提交dml语句,其默认值为off(表示禁止自动提交)。当设置为ON时,每次执行DML
语句都会自动提交。eg:
SQL> show autocommit
autocommit OFF
SQL> set autocommit on
SQL> show autocommit
autocommit IMMEDIATE
(4)colsep
该环境变量用于设置列之间的分隔符,默认分隔符为空格。如果要使用其它分隔符,则使用set命令进行设置。eg:
sql>set colsep |  
SQL> select ename,sal from emp where empno=7788

ENAME     |       SAL
----------|----------
SCOTT     |      3000
(5)feedback
该环境变量用于指定显示反馈行数信息的最低行数,其默认值为6。如果要禁止显示行数反馈信息,则将feedback
设置为off。假设只要有查询结果就返回行数,那么可以将该环境变量设置为1.eg:
sql>set feedback 1
sql>select ename,sal from emp where empno=7788;

ENAME     |       SAL
----------|----------
SCOTT     |      3000
已选择 1 行。
(6)heading
该环境变量用于设置是否显示标题,其默认值为on。如果不显示列标题,则设置为off。eg:
sql>set heading off
sql>select ename,sal from emp where empno=7788
SCOTT     |      3000
(7)linesize
该环境变量用于设置行宽度,默认值为80。在默认情况下,如果数据长度超过80个字符,那么在sql*plus中会折
行显示数据结果。要在一行中显示全部数据,应该设置更大的值。eg:
(8)pagesize
该环境变量用于设置每页所显示的行数,默认值为14
set pagesize 0;   //输出每页行数,缺省为24,为了避免分页,可设定为0。
(9)long
该环境变量用于设置long和lob类型列的显示长度。默认值为80,也就是说当查询long或lob列时,只会显示该列的前80个字符,
应该设置更大的值。eg:
sql>show long
long 80
sql>set long 300
(10)serveroutput
该环境变量用于控制服务器输出,其默认值为off,表示禁止服务器输出。在默认情况下,当调用dbms_output包时,
不会在sql*plus屏幕上显示输出结果。在调用dbms_output包时,为了在屏幕上输出结果,必须要将serveroutput设置
为on。eg:
sql>set serveroutput on
sql>exec dbms_output.put_line('hello')
(11)termout
该环境变量用于控制sql脚本的输出,其默认值为ON。当使用默认值时,如果sql脚本有输出结果,则会在屏幕上输出
显示结果,如果设置为OFF,则不会在屏幕上输出sql脚本。eg:
SQL> set termout off
SQL> @c:\a
(12)time
该环境变量用于设置在sql提示符前是否显示系统时间,默认值为off,表示禁止显示系统时间。如果设置为on,
则在sql提示符前会显示系统时间.eg:
SQL> set time on
12:09:59 SQL>
(13)timing
该环境变量用于设置是否要显示sql语句执行时间,默认值为off,表示不会显示sql语句执行时间。如果设置为
ON,则会显示sql语句执行时间。eg:
sql>set timing on
SQL> select count(*) from emp;

COUNT(*)
----------
        14

已选择 1 行。

已用时间: 00: 00: 00.03
(14)trimspool
set trimout on;   //去除标准输出每行的拖尾空格,缺省为off
set trimspool on;  //去除重定向(spool)输出每行的拖尾空格,缺省为off

如果trimspool设置为on,将移除spool文件中的尾部空格 ,trimout同trimspool功能相似,只不过对象是控制台。
If trimspool is set to on, it will remove trailing blanks in spooled files.
See also trimout which does the same thing to the output to the console (terminal).
eg:
set trimspool off
spool c:\temp\trimspool.txt
declare
v_name varchar2(30);
begin
SELECT table_name into v_name
FROM all_tables
WHERE rownum =1;
dbms_output.put_line(v_name);
end;
/
set trimspool on
declare
v_name varchar2(30);
begin
SELECT table_name into v_name
FROM all_tables
WHERE rownum =1;
dbms_output.put_line(v_name);
end;
/
spool off

-- from ITPUB

文章来源:http://blog.163.com/ccbobo_cat/blog/static/32099462200932325331787
posted @ 2009-04-23 14:54 C.B.K 阅读(1388) | 评论 (0)编辑 收藏
如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段。

     我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法。KMP算法是拿来处理字符串匹配的。换句话说,给你两个字符串,你需要回 答,B串是否是A串的子串(A串是否包含B串)。比如,字符串A="I'm matrix67",字符串B="matrix",我们就说B是A的子串。你可以委婉地问你的MM:“假如你要向你喜欢的人表白的话,我的名字是你的告白 语中的子串吗?”
     解决这类问题,通常我们的方法是枚举从A串的什么位置起开始与B匹配,然后验证是否匹配。假如A串长度为n,B串长度为m,那么这种方法的复杂度是O (mn)的。虽然很多时候复杂度达不到mn(验证时只看头一两个字母就发现不匹配了),但我们有许多“最坏情况”,比如,A= "aaaaaaaaaaaaaaaaaaaaaaaaaab",B="aaaaaaaab"。我们将介绍的是一种最坏情况下O(n)的算法(这里假设 m<=n),即传说中的KMP算法。
     之所以叫做KMP,是因为这个算法是由Knuth、Morris、Pratt三个提出来的,取了这三个人的名字的头一个字母。这时,或许你突然明白了 AVL 树为什么叫AVL,或者Bellman-Ford为什么中间是一杠不是一个点。有时一个东西有七八个人研究过,那怎么命名呢?通常这个东西干脆就不用人名 字命名了,免得发生争议,比如“3x+1问题”。扯远了。
     个人认为KMP是最没有必要讲的东西,因为这个东西网上能找到很多资料。但网上的讲法基本上都涉及到“移动(shift)”、“Next函数”等概念,这 非常容易产生误解(至少一年半前我看这些资料学习KMP时就没搞清楚)。在这里,我换一种方法来解释KMP算法。

     假如,A="abababaababacb",B="ababacb",我们来看看KMP是怎么工作的。我们用两个指针i和j分别表示,A[i-j+ 1..i]与B[1..j]完全相等。也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前 j个字符(j当然越大越好),现在需要检验A[i+1]和B[j+1]的关系。当A[i+1]=B[j+1]时,i和j各加一;什么时候j=m了,我们就 说B是A的子串(B串已经整完了),并且可以根据这时的i值算出匹配的位置。当A[i+1]<>B[j+1],KMP的策略是调整j的位置 (减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配(从而使得i和j能继续增加)。我们看一看当 i=j=5时的情况。

     i   = 1 2 3 4 5 6 7 8 9 ……
     A = a b a b a b a a b a b …
     B = a b a b a c b
     j =   1 2 3 4 5 6 7


     此时,A[6]<>B[6]。这表明,此时j不能等于5了,我们要把j改成比它小的值j'。j'可能是多少呢?仔细想一下,我们发现,j'必 须要使得B[1..j]中的头j'个字母和末j'个字母完全相等(这样j变成了j'后才能继续保持i和j的性质)。这个j'当然要越大越好。在这里,B [1..5]="ababa",头3个字母和末3个字母都是"aba"。而当新的j为3时,A[6]恰好和B[4]相等。于是,i变成了6,而j则变成了 4:

     i   = 1 2 3 4 5 6 7 8 9 ……
     A = a b a b a b a a b a b …
     B =       a b a b a c b
     j =         1 2 3 4 5 6 7


     从上面的这个例子,我们可以看到,新的j可以取多少与i无关,只与B串有关。我们完全可以预处理出这样一个数组P[j],表示当匹配到B数组的第j个字母 而第j+1个字母不能匹配了时,新的j最大是多少。P[j]应该是所有满足B[1..P[j]]=B[j-P[j]+1..j]的最大值。
     再后来,A[7]=B[5],i和j又各增加1。这时,又出现了A[i+1]<>B[j+1]的情况:

     i   = 1 2 3 4 5 6 7 8 9 ……
     A = a b a b a b a a b a b …
     B =       a b a b a c b
     j =        1 2 3 4 5 6 7


     由于P[5]=3,因此新的j=3:

     i = 1 2 3 4 5 6 7 8 9 ……
     A = a b a b a b a a b a b …
     B =             a b a b a c b
     j =              1 2 3 4 5 6 7


     这时,新的j=3仍然不能满足A[i+1]=B[j+1],此时我们再次减小j值,将j再次更新为P[3]:

     i = 1 2 3 4 5 6 7 8 9 ……
     A = a b a b a b a a b a b …
     B =                   a b a b a c b
     j =                    1 2 3 4 5 6 7


     现在,i还是7,j已经变成1了。而此时A[8]居然仍然不等于B[j+1]。这样,j必须减小到P[1],即0:

     i = 1 2 3 4 5 6 7 8 9 ……
     A = a b a b a b a a b a b …
     B =                      a b a b a c b
     j =                    0 1 2 3 4 5 6 7


     终于,A[8]=B[1],i变为8,j为1。事实上,有可能j到了0仍然不能满足A[i+1]=B[j+1](比如A[8]="d"时)。因此,准确的说法是,当j=0了时,我们增加i值但忽略j直到出现A[i]=B[1]为止。
     这个过程的代码很短(真的很短),我们在这里给出:

程序代码
j:=0;
for i:=1 to n do
begin
   while (j>0) and (B[j+1]<>A[i]) do j:=P[j];
   if B[j+1]=A[i] then j:=j+1;
   if j=m then
   begin
       writeln('Pattern occurs with shift ',i-m);
       j:=P[j];
   end;
end;


     最后的j:=P[j]是为了让程序继续做下去,因为我们有可能找到多处匹配。
     这个程序或许比想像中的要简单,因为对于i值的不断增加,代码用的是for循环。因此,这个代码可以这样形象地理解:扫描字符串A,并更新可以匹配到B的什么位置。

     现在,我们还遗留了两个重要的问题:一,为什么这个程序是线性的;二,如何快速预处理P数组。
     为什么这个程序是O(n)的?其实,主要的争议在于,while循环使得执行次数出现了不确定因素。我们将用到时间复杂度的摊还分析中的主要策略,简单地 说就是通过观察某一个变量或函数值的变化来对零散的、杂乱的、不规则的执行次数进行累计。KMP的时间复杂度分析可谓摊还分析的典型。我们从上述程序的j 值入手。每一次执行while循环都会使j减小(但不能减成负的),而另外的改变j值的地方只有第五行。每次执行了这一行,j都只能加1;因此,整个过程 中j最多加了n个1。于是,j最多只有n次减小的机会(j值减小的次数当然不能超过n,因为j永远是非负整数)。这告诉我们,while循环总共最多执行 了n次。按照摊还分析的说法,平摊到每次for循环中后,一次for循环的复杂度为O(1)。整个过程显然是O(n)的。这样的分析对于后面P数组预处理 的过程同样有效,同样可以得到预处理过程的复杂度为O(m)。
     预处理不需要按照P的定义写成O(m^2)甚至O(m^3)的。我们可以通过P[1],P[2],...,P[j-1]的值来获得P[j]的值。对于刚才 的B="ababacb",假如我们已经求出了P[1],P[2],P[3]和P[4],看看我们应该怎么求出P[5]和P[6]。P[4]=2,那么P [5]显然等于P[4]+1,因为由P[4]可以知道,B[1,2]已经和B[3,4]相等了,现在又有B[3]=B[5],所以P[5]可以由P[4] 后面加一个字符得到。P[6]也等于P[5]+1吗?显然不是,因为B[ P[5]+1 ]<>B[6]。那么,我们要考虑“退一步”了。我们考虑P[6]是否有可能由P[5]的情况所包含的子串得到,即是否P[6]=P[ P[5] ]+1。这里想不通的话可以仔细看一下:

         1 2 3 4 5 6 7
     B = a b a b a c b
     P = 0 0 1 2 3 ?


     P[5]=3是因为B[1..3]和B[3..5]都是"aba";而P[3]=1则告诉我们,B[1]和B[5]都是"a"。既然P[6]不能由P [5]得到,或许可以由P[3]得到(如果B[2]恰好和B[6]相等的话,P[6]就等于P[3]+1了)。显然,P[6]也不能通过P[3]得到,因 为B[2]<>B[6]。事实上,这样一直推到P[1]也不行,最后,我们得到,P[6]=0。
     怎么这个预处理过程跟前面的KMP主程序这么像呢?其实,KMP的预处理本身就是一个B串“自我匹配”的过程。它的代码和上面的代码神似:

程序代码
P[1]:=0;
j:=0;
for i:=2 to m do
begin
   while (j>0) and (B[j+1]<>B[i]) do j:=P[j];
   if B[j+1]=B[i] then j:=j+1;
   P[i]:=j;
end;


     最后补充一点:由于KMP算法只预处理B串,因此这种算法很适合这样的问题:给定一个B串和一群不同的A串,问B是哪些A串的子串。

     串匹配是一个很有研究价值的问题。事实上,我们还有后缀树,自动机等很多方法,这些算法都巧妙地运用了预处理,从而可以在线性的时间里解决字符串的匹配。我们以后来说。

Matrix67原创


文章来源:http://blog.163.com/ccbobo_cat/blog/static/32099462200931645748543
posted @ 2009-04-16 16:58 C.B.K 阅读(74) | 评论 (0)编辑 收藏
(1)给金额添加逗号
import java.text.*;
NumberFormat formater = new DecimalFormat("###,###.##");
formater.format(12342351432534.24565);
(2)日期格式换
Date now = new Date();
SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd");
formater.format(now());
SimpleDateFormat

模式字母(所有其他字符 'A''Z''a''z' 都被保留):

字母 日期或时间元素 表示 示例
G Era 标志符 Text AD
y Year 1996; 96
M 年中的月份 Month July; Jul; 07
w 年中的周数 Number 27
W 月份中的周数 Number 2
D 年中的天数 Number 189
d 月份中的天数 Number 10
F 月份中的星期 Number 2
E 星期中的天数 Text Tuesday; Tue
a Am/pm 标记 Text PM
H 一天中的小时数(0-23) Number 0
k 一天中的小时数(1-24) Number 24
K am/pm 中的小时数(0-11) Number 0
h am/pm 中的小时数(1-12) Number 12
m 小时中的分钟数 Number 30
s 分钟中的秒数 Number 55
S 毫秒数 Number 978
z 时区 General time zone Pacific Standard Time; PST; GMT-08:00
Z 时区 RFC 822 time zone -0800
模式字母通常是重复的,其数量确定其精确表示:
  • Text: 对于格式化来说,如果模式字母的数量大于或等于 4,则使用完全形式;否则,在可用的情况下使用短形式或缩写形式。对于分析来说,两种形式都是可接受的,与模式字母的数量无关。
  • Number: 对于格式化来说,模式字母的数量是最小的数位,如果数位不够,则用 0 填充以达到此数量。对于分析来说,模式字母的数量被忽略,除非必须分开两个相邻字段。
  • Year: 对于格式化来说,如果模式字母的数量为 2,则年份截取为 2 位数,否则将年份解释为 number。 SimpleDateFormat

    示例

    以下示例显示了如何在美国语言环境中解释日期和时间模式。给定的日期和时间为美国太平洋时区的本地时间 2001-07-04 12:08:56。
    日期和时间模式 结果
    "yyyy.MM.dd G 'at' HH:mm:ss z" 2001.07.04 AD at 12:08:56 PDT
    "EEE, MMM d, ''yy" Wed, Jul 4, '01
    "h:mm a" 12:08 PM
    "hh 'o''clock' a, zzzz" 12 o'clock PM, Pacific Daylight Time
    "K:mm a, z" 0:08 PM, PDT
    "yyyyy.MMMMM.dd GGG hh:mm aaa" 02001.July.04 AD 12:08 PM
    "EEE, d MMM yyyy HH:mm:ss Z" Wed, 4 Jul 2001 12:08:56 -0700
    "yyMMddHHmmssZ" 010704120856-0700
    "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 2001-07-04T12:08:56.235-0700


文章来源:http://blog.163.com/ccbobo_cat/blog/static/32099462200931621628957
posted @ 2009-04-16 14:16 C.B.K 阅读(72) | 评论 (0)编辑 收藏

(一)

开门见山.今天我要说的是不用HQL执行SAVE和DELETE方法,用hibernate的executeQuery来执行SQL

其原理如下(从SessionFactory里获得个Session,在调用session的connection方法,通过Statement来执行静态SQL,最后执行executeQuery就可以了)具体如下:

protected Session session = null; protected Transaction tr = null;

String sql = "insert into as_dept2role(roleid,dept_id)value('"+roleId+"','"+deptId+"')"; session=HibernateSessionFactory.getSession();                                                                               

   session.beginTransaction();
//获取connection,执行静态SQL
Statement state = session.connection().createStatement();
state.executeQuery(sql);
tr.commit(); session.close();

当然关于 关闭SESSION 这些方法我写的简单些,主要是为了写 执行SQL这些方法

对于删除只要写个删除语句就可以了

:Transaction tr = session.beginTransaction();

* session.connection() 方法过时 用下面来代替 *
DataSource ds= SessionFactoryUtils.getDataSource(getSessionFactory());
conn=ds.getConnection();

============================================

(二)

public Object get(Class cls, String szId) {
Object obj = this.getHibernateTemplate().get(cls, szId);
return obj;
}
obj.getsessionFaction.opensession返回session


Session session = dao.openSession();
Connection conn = session.connection();
List recordList = new ArrayList();

StringBuffer sql = new StringBuffer();
sql.append("select b.user_name, c.org_name ");
sql.append("from orgmeetinglinkman a, am_user b, organization c ");
sql.append("where a.login_name = b.login_name ");
sql.append("and a.org_id = c.org_id ");

PreparedStatement ps = conn.prepareStatement(sql.toString());
ResultSet rs = ps.execu

============================================

(三)

public List findWithSQL(final String sql) {
   List list = (List) this.getHibernateTemplate().execute(
     new HibernateCallback() {
      public Object doInHibernate(Session session)
        throws SQLException, HibernateException {
       SQLQuery query = session.createSQLQuery(sql);
       query.addScalar("NX",new org.hibernate.type.StringType());
       List children = query.list();
       return children;
      }
     });
   return list;
}

/**
* 查询并返回结果集,结果集中的内容已经都转为了字符串
*/
public List<List<String>> findSql(final String sql) {
   // TODO Auto-generated method stub
   System.out.println("findSql---sql1----->"+sql);
   List<List<String>> mainObjList= (List<List<String>>) getHibernateTemplate().execute(new HibernateCallback() {

    public Object doInHibernate(Session session)
      throws HibernateException, SQLException {

    
     int n=-1;
     Connection con=null;
     PreparedStatement stmt=null;
     ResultSet rs=null;
    
     try
     {
     
      DataSource ds= SessionFactoryUtils.getDataSource(getSessionFactory());
      if(ds==null)
      {
       throw new SQLException("get dataSource is null");
      }
      con=ds.getConnection();
      System.out.println("findSql---sql2----->"+sql);
      stmt=con.prepareStatement(sql);
      rs=stmt.executeQuery();
     
     } catch (HibernateException e)
     {
      // TODO Auto-generated catch block
      e.printStackTrace();
     } catch (SQLException e)
     {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    
     List<List<String>> list=new ArrayList<List<String>>();//每行为一个list
     try
     {
      ResultSetMetaData rsmd=rs.getMetaData();
      int colsNum=rsmd.getColumnCount();//取得列数
      int rsNum=0;
      while(rs.next())
      {
       rsNum++;
       System.out.println("rsNum==="+rsNum+" ");
       List<String> subList=new ArrayList<String> ();//每列的类型为string
       for(int i=1;i<=colsNum;i++)
       {
        System.out.println("\ti==="+i);
        //int type= rsmd.getColumnType(i);
        String columnType=getDataType(rsmd.getColumnType(i),rsmd.getScale(i));  
        String val="";
        if(columnType.equalsIgnoreCase("Date"))
        {
         Timestamp timest= rs.getTimestamp(i);
         if(timest!=null)
         {
          long times=timest.getTime();
          Date date=new Date(times);
          SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.CHINA);
          val=df.format(date);
         }
        }
        else if(columnType.equalsIgnoreCase("Number"))
        {
         Object obj=rs.getObject(i);
         if(obj!=null)
         {
          int m=rs.getInt(i);
          val=Integer.toString(m);
         }
        }
        else if(columnType.equalsIgnoreCase("blob"))
        {
         val="不支持blob数据的读取";
        }
        else if(columnType.equalsIgnoreCase("clob"))
        {
         val=getOracleClobField(rs, i);
        
        }
        else
        {
         val=rs.getString(i);
        }
        if(val==null)
        {
         val="";
        }
        subList.add(val);
       }
       if(subList.size()>0)
       {
        list.add(subList);
       }
      }
     }
     catch(Exception ex5)
     {
      ex5.printStackTrace();
      System.out.println("ex5.getMessage="+ex5.getMessage());
      list=null;
     }
     finally
     {
      try {
       if (rs != null) {
        rs.close();
        rs = null;
       }
      } catch (Exception e2) {
       // TODO: handle exception
       e2.printStackTrace();
       System.out.println("e2.getMessage="+e2.getMessage());
      }
      try {
       if (stmt != null) {
        stmt.close();
        stmt = null;
       }
      } catch (Exception e3) {
       // TODO: handle exception
       e3.printStackTrace();
       System.out.println("e3.getMessage="+e3.getMessage());
      }
      try {
       if (con != null) {
        con.close();
        con = null;
       }
      } catch (Exception e4) {
       // TODO: handle exception
       e4.printStackTrace();
       System.out.println("e4.getMessage="+e4.getMessage());
      }
     
     }
     return list;
    }

   });
   return mainObjList;
}

// String   columnType=getDataType(rmd.getColumnType(i),rmd.getScale(i));  
private String getOracleClobField(ResultSet rset, int index)
     throws Exception
{
     StringBuffer buffS = new StringBuffer();
     Clob clob = rset.getClob(index + 1);
     if(clob == null)
         return " ";
     Reader reader = clob.getCharacterStream();
     char buff[] = new char[1024];
     for(int len = 0; (len = reader.read(buff)) != -1;)
         buffS.append(buff, 0, len);
      return buffS.toString();
}
    
private   static   String   getDataType(int   type,int   scale)
{  
   String   dataType="";  

   switch(type){  
    case   Types.LONGVARCHAR:   //-1  
     dataType="Long";  
      break;  
    case   Types.CHAR:         //1  
     dataType="Character";  
          break;  
    case   Types.NUMERIC:   //2  
     switch(scale)
     {  
         case   0:  
             dataType="Number";  
             break;  
         case   -127:  
             dataType="Float";  
             break;  
         default:  
             dataType="Number";  
     }  
     break;  
    case   Types.VARCHAR:     //12  
     dataType="String";  
        break;  
    case   Types.DATE:     //91  
     dataType="Date";  
        break;  
    case   Types.TIMESTAMP:   //93  
     dataType="Date";  
        break;  
    case   Types.BLOB   :  
        dataType="Blob";  
        break;  
    default:  
        dataType="String";  
    }  
    return   dataType;
}


文章来源:http://blog.163.com/ccbobo_cat/blog/static/32099462200931511221288
posted @ 2009-04-15 23:22 C.B.K 阅读(18768) | 评论 (1)编辑 收藏
  匈牙利命名法
  匈牙利命名法是一种编程时的命名规范。基本原则是:变量名=属性+类型+对象描述,其中每一对象的名称都要求有明确含义,可以取对象名字全称或名字的一部分。命名要基于容易记忆容易理解的原则。保证名字的连贯性是非常重要的。
  举例来说,表单的名称为form,那么在匈牙利命名法中可以简写为frm,则当表单变量名称为 Switchboard时,变量全称应该为 frmSwitchboard。这样可以很容易从变量名看出Switchboard是一个表单,同样,如果此变量类型为标签,那么就应命名成 lblSwitchboard。可以看出,匈牙利命名法非常便于记忆,而且使变量名非常清晰易懂,这样,增强了代码的可读性,方便各程序员之间相互交流代 码。
  据说这种命名法是一位叫 Charles Simonyi 的匈牙利程序员发明的,后来他在微软呆了几年,于是这种命名法就通过微软的各种产品和文档资料向世界传播开了。现在,大部分程序员不管自己使用什么软件进 行开发,或多或少都使用了这种命名法。这种命名法的出发点是把变量名按:属性+类型+对象描述的顺序组合起来,以使程序员作变量时对变量的类型和其它属性 有直观的了解,下面是HN变量命名规范,其中也有一些是我个人的偏向:
  属性部分
  全局变量
  g_
  常量
  c_
  c++类成员变量
  m_
  静态变量
  s_
  类型部分
  指针
  p
  函数
  fn
  无效
  v
  句柄
  h
  长整型
  l
  布尔
  b
  浮点型(有时也指文件)
  f
  双字
  dw
  字符串
  sz
  短整型
  n
  双精度浮点
  d
  计数
  c(通常用cnt)
  字符
  ch(通常用c)
  整型
  i(通常用n)
  字节
  by
  字
  w
  实型
  r
  无符号
  u
  描述部分
  最大
  Max
  最小
  Min
  初始化
  Init
  临时变量
  T(或Temp)
  源对象
  Src
  目的对象
  Dest
  这里顺便写几个例子:
  hwnd : h 是类型描述,表示句柄, wnd 是变量对象描述,表示窗口,所以 hwnd 表示窗口句柄;
  pfnEatApple : pfn 是类型描述,表示指向函数的指针, EatApple 是变量对象描述,所以它表示
  指向 EatApple 函数的函数指针变量。
  g_cch : g_ 是属性描述,表示全局变量,c 和 ch 分别是计数类型和字符类型,一起表示变量类
  型,这里忽略了对象描述,所以它表示一个对字符进行计数的全局变量。
  上面就是HN命名法的一般规则。
  小结:匈牙利命名法
  匈牙利命名法
  MFC、句柄、控件及结构的命名规范 Windows类型 样本变量 MFC类 样本变量
  HWND hWnd; CWnd* pWnd;
  HDLG hDlg; CDialog* pDlg;
  HDC hDC; CDC* pDC;
  HGDIOBJ hGdiObj; CGdiObject* pGdiObj;
  HPEN hPen; CPen* pPen;
  HBRUSH hBrush; CBrush* pBrush;
  HFONT hFont; CFont* pFont;
  HBITMAP hBitmap; CBitmap* pBitmap;
  HPALETTE hPaltte; CPalette* pPalette;
  HRGN hRgn; CRgn* pRgn;
  HMENU hMenu; CMenu* pMenu;
  HWND hCtl; CState* pState;
  HWND hCtl; CButton* pButton;
  HWND hCtl; CEdit* pEdit;
  HWND hCtl; CListBox* pListBox;
  HWND hCtl; CComboBox* pComboBox;
  HWND hCtl; CScrollBar* pScrollBar;
  HSZ hszStr; CString pStr;
  POINT pt; CPoint pt;
  SIZE size; CSize size;
  RECT rect; CRect rect;
  一般前缀命名规范 前缀 类型 实例
  C 类或结构 CDocument,CPrintInfo
  m_ 成员变量 m_pDoc,m_nCustomers
  变量命名规范 前缀 类型 描述 实例
  ch char 8位字符 chGrade
  ch TCHAR 如果_UNICODE定义,则为16位字符 chName
  b BOOL 布尔值 bEnable
  n int 整型(其大小依赖于操作系统) nLength
  n UINT 无符号值(其大小依赖于操作系统) nHeight
  w WORD 16位无符号值 wPos
  l LONG 32位有符号整型 lOffset
  dw DWORD 32位无符号整型 dwRange
  p * 指针 pDoc
  lp FAR* 远指针 lpszName
  lpsz LPSTR 32位字符串指针 lpszName
  lpsz LPCSTR 32位常量字符串指针 lpszName
  lpsz LPCTSTR 如果_UNICODE定义,则为32位常量字符串指针 lpszName
  h handle Windows对象句柄 hWnd
  lpfn callback 指向CALLBACK函数的远指针
  前缀 符号类型 实例 范围
  IDR_ 不同类型的多个资源共享标识 IDR_MAIINFRAME 1~0x6FFF
  IDD_ 对话框资源 IDD_SPELL_CHECK 1~0x6FFF
  HIDD_ 对话框资源的Help上下文 HIDD_SPELL_CHECK 0x20001~0x26FF
  IDB_ 位图资源 IDB_COMPANY_LOGO 1~0x6FFF
  IDC_ 光标资源 IDC_PENCIL 1~0x6FFF
  IDI_ 图标资源 IDI_NOTEPAD 1~0x6FFF
  ID_ 来自菜单项或工具栏的命令 ID_TOOLS_SPELLING 0x8000~0xDFFF
  HID_ 命令Help上下文 HID_TOOLS_SPELLING 0x18000~0x1DFFF
  IDP_ 消息框提示 IDP_INVALID_PARTNO 8~0xDEEF
  HIDP_ 消息框Help上下文 HIDP_INVALID_PARTNO 0x30008~0x3DEFF
  IDS_ 串资源 IDS_COPYRIGHT 1~0x7EEF
  IDC_ 对话框内的控件 IDC_RECALC 8~0xDEEF
  Microsoft MFC宏命名规范 名称 类型
  _AFXDLL 唯一的动态连接库(Dynamic Link Library,DLL)版本
  _ALPHA 仅编译DEC Alpha处理器
  _DEBUG 包括诊断的调试版本
  _MBCS 编译多字节字符集
  _UNICODE 在一个应用程序中打开Unicode
  AFXAPI MFC提供的函数
  CALLBACK 通过指针回调的函数
  库标识符命名法 标识符 值和含义
  u ANSI(N)或Unicode(U)
  d 调试或发行:D = 调试;忽略标识符为发行。
  静态库版本命名规范 库 描述
  NAFXCWD.LIB 调试版本:MFC静态连接库
  NAFXCW.LIB 发行版本:MFC静态连接库
  UAFXCWD.LIB 调试版本:具有Unicode支持的MFC静态连接库
  UAFXCW.LIB 发行版本:具有Unicode支持的MFC静态连接库
  动态连接库命名规范 名称 类型
  _AFXDLL 唯一的动态连接库(DLL)版本
  WINAPI Windows所提供的函数
  Windows.h中新的命名规范 类型 定义描述
  WINAPI 使用在API声明中的FAR PASCAL位置,如果正在编写一个具有导出API人口点的DLL,则可以在自己的API中使用该类型
  CALLBACK 使用在应用程序回叫例程,如窗口和对话框过程中的FAR PASCAL的位置
  LPCSTR 与LPSTR相同,只是LPCSTR用于只读串指针,其定义类似(const char FAR*)
  UINT 可移植的无符号整型类型,其大小由主机环境决定(对于Windows NT和Windows 9x为32位);它是unsigned int的同义词
  LRESULT 窗口程序返回值的类型
  LPARAM 声明lParam所使用的类型,lParam是窗口程序的第四个参数
  WPARAM 声明wParam所使用的类型,wParam是窗口程序的第三个参数
  LPVOID 一般指针类型,与(void *)相同,可以用来代替LPSTR
  --------------------------------------------------------------------------------
  抨击匈牙利命名法
  匈牙利命名法是一种编程时的命名规范。命名规范是程序书写规范中最重要也是最富争议的地方,自 古乃兵家必争之地。命名规范有何用?四个字:名正言顺。用二分法,命名规范分为好的命名规范和坏的命名规范,也就是说名正言顺的命名规范和名不正言不顺的 命名规范。好的舞鞋是让舞者感觉不到其存在的舞鞋,坏的舞鞋是让舞者带着镣铐起舞。一个坏的命名规范具有的破坏力比一个好的命名规范具有的创造力要大得 多。
  本文要证明的是:匈牙利命名法是一个坏的命名规范。本文的作用范围为静态强类型编程语言。本文的分析范本为C语言和C++语言。下文中的匈法为匈牙利命名法的简称。
  一 匈牙利命名法的成本
  匈法的表现形式为给变量名附加上类型名前缀,例 如:nFoo,szFoo,pFoo,cpFoo分别表示整型变量,字符串型变量,指针型变量和常指针型变量。可以看出,匈法将变量的类型信息从单一地点 (声明变量处)复制到了多个地点(使用变量处),这是冗余法。冗余法的成本之一是要维护副本的一致性。这个成本在编写和维护代码的过程中需要改变变量的类 型时付出。冗余法的成本之二是占用了额外的空间。一个优秀的书写者会自觉地遵从一个法则:代码最小组织单位的长度以30个自然行以下为宜,如果超过50行 就应该重新组织。一个变量的书写空间会给这一法则添加不必要的难度。
  二 匈牙利命名法的收益
  这里要证明匈牙利命名法的收益是含糊的,无法预期的。
  范本1:strcpy(pstrFoo,pcstrFoo2) Vs strcpy(foo,foo2)
  匈法在这里有什么收益呢?我看不到。没有一个程序员会承认自己不知道strcpy函数的参数类型吧。
  范本2:unknown_function(nFoo) Vs unknown_function(foo)
  匈法在这里有什么收益呢?我看不到。对于一个不知道确定类型的函数,程序员应该去查看该函数的 文档,这是一种成本。使用匈法的唯一好处是看代码的人知道这个函数要求一个整型参数,这又有什么用处呢?函数是一种接口,参数的类型仅仅是接口中的一小部 分。诸如函数的功能、出口信息、线程安全性、异常安全性、参数合法性等重要信息还是必须查阅文档。
  范本3:nFoo=nBar Vs foo=bar
  匈法在这里有什么收益呢?我看不到。使用匈法的唯一好处是看代码的人知道这里发生了一个整型变 量的复制动作,听起来没什么问题,可以安心睡大觉了。如果他看到的是nFoo=szBar,可能会从美梦中惊醒。且慢,事情真的会是这样吗?我想首先被惊 醒的应该是编译器。另一方面,nFoo=nBar只是在语法上合法而已,看代码的人真正关心的是语义的合法性,匈法对此毫无帮助。另一方面,一个优秀的书 写者会自觉地遵从一个法则:代码最小组织单位中的临时变量以一两个为宜,如果超过三个就应该重新组织。结合前述第一个法则,可以得出这样的结论:易于理解 的代码本身就应该是易于理解的,这是代码的内建高质量。好的命名规范对内建高质量的助益相当有限,而坏的命名规范对内建高质量的损害比人们想象的要大。
  三 匈牙利命名法的实施
  这里要证明匈牙利命名法在C语言是难以实施的,在C++语言中是无法实施的。从逻辑上讲,对匈法的收益做出否定的结论以后,再来论证匈法的可行性,是画蛇添足。不过有鉴于小马哥曾让已射杀之敌死灰复燃,我还是再踏上一支脚为妙。
  前面讲过,匈法是类型系统的冗余,所以实施匈法的关键是我们是否能够精确地对类型系统进行复制。这取决于类型系统的复杂性。
  先来看看C语言:
  1.内置类型:int,char,float,double 复制为 n,ch,f,d?好像没有什么问题。不过谁来告诉我void应该怎么表示?
  2.组合类型:array,union,enum,struct 复制为 a,u,e,s?好像比较别扭。
  这里的难点不是为主类型取名,而是为副类型取名。an表示整型数组?sfoo,sbar表示结构foo,结构bar?ausfoo表示联合结构foo数组?累不累啊。
  3.特殊类型:pointer。pointer在理论上应该是组合类型,但是在C语言中可以认为是内置类型,因为C语言并没有非常严格地区分不同的指针类型。下面开始表演:pausfoo表示联合结构foo数组指针?ppp表示指针的指针的指针?
  噩梦还没有结束,再来看看类型系统更阿为丰富的C++语言:
  1.class:如果说C语言中的struct还可以用stru搪塞过去的话,不要梦想用 cls来搪塞C++中的class。严格地讲,class根本就并不是一个类型,而是创造类型的工具,在C++中,语言内置类型的数量和class创造的 用户自定义类型的数量相比完全可以忽略不计。stdvectorFoo表示标准库向量类型变量Foo?疯狂的念头。
  2.命名空间:boostfilesystemiteratorFoo,表示boost空间filesystem子空间遍历目录类型变量Foo?程序员要崩溃了。
  3.模板:你记得std::map<std::string,std::string>类型的确切名字吗?我是记不得了,好像超过255个字符,还是饶了我吧。
  4.模板参数:template <class T, class BinaryPredicate>const T& max(const T& a, const T& b, BinaryPredicate comp) 聪明的你,请用匈法为T命名。上帝在发笑。
  5.类型修饰:static,extern,mutable,register,volatile,const,short,long,unsigned 噩梦加上修饰是什么?还是噩梦。

文章来源:http://blog.163.com/ccbobo_cat/blog/static/32099462200931411226261
posted @ 2009-04-14 23:02 C.B.K 阅读(82) | 评论 (0)编辑 收藏
仅列出标题
共2页: 上一页 1 2