愚人码头

知耻而后勇,知不足而进
随笔 - 33, 文章 - 1, 评论 - 26, 引用 - 0
数据加载中……

2006年3月6日

对hibernate的新认识

     摘要:   阅读全文

posted @ 2008-01-30 11:14 船夫 阅读(1941) | 评论 (7)编辑 收藏

转:Javascript事件处理

     摘要:   阅读全文

posted @ 2007-12-26 13:00 船夫 阅读(337) | 评论 (0)编辑 收藏

转:提升JSP应用程序的七大绝招

提升JSP应用程序的七大绝招
你时常被客户抱怨JSP页面响应速度很慢吗?你想过当客户访问次数剧增时,你的WEB应用能承受日益增加的访 问量吗?本文讲述了调整JSP和servlet的一些非常实用的方法,它可使你的servlet和JSP页面响应更快,扩展性更强。而且在用户数增加的情 况下,系统负载会呈现出平滑上长的趋势。在本文中,我将通过一些实际例子和配置方法使得你的应用程序的性能有出人意料的提升。其中,某些调优技术是在你的 编程工作中实现的。而另一些技术是与应用服务器的配置相关的。在本文中,我们将详细地描述怎样通过调整servlet和JSP页面,来提高你的应用程序的 总体性能。在阅读本文之前,假设你有基本的servlet和JSP的知识。
方法一:在servlet的init()方法中缓存数据

当应用服务器初始化servlet实例之后,为客户端请求提供服务之前,它会调用这个servlet的init()方法。在一个servlet的生命周 期中,init()方法只会被调用一次。通过在init()方法中缓存一些静态的数据或完成一些只需要执行一次的、耗时的操作,就可大大地提高系统性能。

例如,通过在init()方法中建立一个JDBC连接池是一个最佳例子,假设我们是用jdbc2.0的DataSource接口来取得数据库连接,在通 常的情况下,我们需要通过JNDI来取得具体的数据源。我们可以想象在一个具体的应用中,如果每次SQL请求都要执行一次JNDI查询的话,那系统性能将 会急剧下降。解决方法是如下代码,它通过缓存DataSource,使得下一次SQL调用时仍然可以继续利用它:

public class ControllerServlet extends HttpServlet
{
private javax.sql.DataSource testDS = null;
public void init(ServletConfig config) throws ServletException
{
super.init(config);
Context ctx = null;
try
{
ctx = new InitialContext();
testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS");
}
catch(NamingException ne)
{
ne.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
}

public javax.sql.DataSource getTestDS()
{
return testDS;
}
...
...
}

方法 2:禁止servlet和JSP 自动重载(auto-reloading)

Servlet/JSP提供了一个实用的技术,即自动重载技术,它为开发人员提供了一个好的开发环境,当你改变servlet和JSP页面后而不必重启 应用服务器。然而,这种技术在产品运行阶段对系统的资源是一个极大的损耗,因为它会给JSP引擎的类装载器(classloader)带来极大的负担。因 此关闭自动重载功能对系统性能的提升是一个极大的帮助。

方法 3: 不要滥用HttpSession

在很多应 用中,我们的程序需要保持客户端的状态,以便页面之间可以相互联系。但不幸的是由于HTTP具有天生无状态性,从而无法保存客户端的状态。因此一般的应用 服务器都提供了session来保存客户的状态。在JSP应用服务器中,是通过HttpSession对像来实现session的功能的,但在方便的同 时,它也给系统带来了不小的负担。因为每当你获得或更新session时,系统者要对它进行费时的序列化操作。你可以通过对HttpSession的以下 几种处理方式来提升系统的性能:

? 如果没有必要,就应该关闭JSP页面中对HttpSession的缺省设置: 如果你没有明确指定的话,每个JSP页面都会缺省地创建一个HttpSession。如果你的JSP中不需要使用session的话,那可以通过如下的JSP页面指示符来禁止它:

<%@ page session="false"%>

? 不要在HttpSession中存放大的数据对像:如果你在HttpSession中存放大的数据对像的话,每当对它进行读写时,应用服务器都将对其进行 序列化,从而增加了系统的额外负担。你在HttpSession中存放的数据对像越大,那系统的性能就下降得越快。

? 当你不需要HttpSession时,尽快地释放它:当你不再需要session时,你可以通过调用HttpSession.invalidate()方法来释放它。

? 尽量将session的超时时间设得短一点:在JSP应用服务器中,有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何操作的话, 系统会将相关的session自动从内存中释放。超时时间设得越大,系统的性能就会越低,因此最好的方法就是尽量使得它的值保持在一个较低的水平。

方法 4: 将页面输出进行压缩

压缩是解决数据冗余的一个好的方法,特别是在网络带宽不够发达的今天。有的浏览器支持gzip(GNU zip)进行来对HTML文件进行压缩,这种方法可以戏剧性地减少HTML文件的下载时间。因此,如果你将servlet或JSP页面生成的HTML页面 进行压缩的话,那用户就会觉得页面浏览速度会非常快。但不幸的是,不是所有的浏览器都支持gzip压缩,但你可以通过在你的程序中检查客户的浏览器是否支 持它。下面就是关于这种方法实现的一个代码片段:

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
OutputStream out = null
String encoding = request.getHeader("Accept-Encoding");
if (encoding != null && encoding.indexOf("gzip") != -1)
{
request.setHeader("Content-Encoding" , "gzip");
out = new GZIPOutputStream(request.getOutputStream());
}
else if (encoding != null && encoding.indexOf("compress") != -1)
{
request.setHeader("Content-Encoding" , "compress");
out = new ZIPOutputStream(request.getOutputStream());
}
else
{
out = request.getOutputStream();
}
...
...
}

方法 5: 使用线程池

应用服务器缺省地为每个不同的客户端请求创建一个线程进行处理,并为它们分派service()方法,当service()方法调用完成后,与之相应的 线程也随之撤消。由于创建和撤消线程会耗费一定的系统资源,这种缺省模式降低了系统的性能。但所幸的是我们可以通过创建一个线程池来改变这种状况。另外, 我们还要为这个线程池设置一个最小线程数和一个最大线程数。在应用服务器启动时,它会创建数量等于最小线程数的一个线程池,当客户有请求时,相应地从池从 取出一个线程来进行处理,当处理完成后,再将线程重新放入到池中。如果池中的线程不够地话,系统会自动地增加池中线程的数量,但总量不能超过最大线程数。 通过使用线程池,当客户端请求急剧增加时,系统的负载就会呈现的平滑的上升曲线,从而提高的系统的可伸缩性。

方法 6: 选择正确的页面包含机制

在JSP中有两种方法可以用来包含另一个页面:1、使用include指示符(<%@ includee file=”test.jsp” %>)。2、使用jsp指示符(<jsp:includee page=”test.jsp” flush=”true”/>)。在实际中我发现,如果使用第一种方法的话,可以使得系统性能更高。

方法 7:正确地确定javabean的生命周期

JSP的一个强大的地方就是对javabean的支持。通过在JSP页面中使用<jsp:useBean>标签,可以将javabean直接插入到一个JSP页面中。它的使用方法如下:

<jsp:useBean id="name" scope="page|request|session|application" class=
"package.className" type="typeName">
</jsp:useBean>

其中scope属性指出了这个bean的生命周期。缺省的生命周期为page。如果你没有正确地选择bean的生命周期的话,它将影响系统的性能。

举例来说,如果你只想在一次请求中使用某个bean,但你却将这个bean的生命周期设置成了session,那当这次请求结束后,这个bean将仍然 保留在内存中,除非session超时或用户关闭浏览器。这样会耗费一定的内存,并无谓的增加了JVM垃圾收集器的工作量。因此为bean设置正确的生命 周期,并在bean的使命结束后尽快地清理它们,会使用系统性能有一个提高

其它一些有用的方法

? 在字符串连接操作中尽量不使用“+”操作符:在java编程中,我们常常使用“+”操作符来将几个字符串连接起来,但你或许从来没有想到过它居然会对系统 性能造成影响吧?由于字符串是常量,因此JVM会产生一些临时的对像。你使用的“+”越多,生成的临时对像就越多,这样也会给系统性能带来一些影响。解决 的方法是用StringBuffer对像来代替“+”操作符。

? 避免使用System.out.println()方法:由于System.out.println()是一种同步调用,即在调用它时,磁盘I/O操作必 须等待它的完成,因此我们要尽量避免对它的调用。但我们在调试程序时它又是一个必不可少的方便工具,为了解决这个矛盾,我建议你最好使用Log4j工具 (http://Jakarta.apache.org ),它既可以方便调试,而不会产生System.out.println()这样的方法。

? ServletOutputStream 与 PrintWriter的权衡:使用PrintWriter可能会带来一些小的开销,因为它将所有的原始输出都转换为字符流来输出,因此如果使用它来作为 页面输出的话,系统要负担一个转换过程。而使用ServletOutputStream作为页面输出的话就不存在一个问题,但它是以二进制进行输出的。因 此在实际应用中要权衡两者的利弊。

总结

本文的目的是通过对servlet和JSP的一些调优技术来极大地提高你 的应用程序的性能,并因此提升整个J2EE应用的性能。通过这些调优技术,你可以发现其实并不是某种技术平台(比如J2EE和.NET之争)决定了你的应 用程序的性能,重要是你要对这种平台有一个较为深入的了解,这样你才能从根本上对自己的应用程序做一个优化! 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1448910

posted @ 2007-12-25 17:04 船夫 阅读(222) | 评论 (0)编辑 收藏

转载一篇测试笔记,用于备忘

     摘要:   阅读全文

posted @ 2007-12-25 14:43 船夫 阅读(257) | 评论 (0)编辑 收藏

JSP编译过程

很久以来,都知道JSP其实就是Servlet,今天心血来潮,想把里面的具体代码看一遍,并记录心得。
一个编译好的JSP类如下:
public
 final class index_jsp extends HttpJspBase
    
implements JspSourceDependent
//上述类为index.jsp被编译后得到的类
//HttpJspBase是extends HttpServlet的一个类
//JspSourceDependent是一个接口,只声明了一个方法、、getDependants(),返回当前page所依赖的文件的名称,文件包括以下几种
//1) files that are included by page directives 
//2) files that are included by include-prelude and include-coda in jsp:config 
//3) files that are tag files and referenced 
//4) TLDs referenced
其核心方法为:
  public void _jspService(HttpServletRequest request, HttpServletResponse response)
        
throws IOException, ServletException{
.
}
该方法重载HttpJspBase中的_jspService方法,进行页面解析,包括对scriptlet的加载,html的生成,自定义Tag的解析等等
HttpJspBase的service再对_jspService再进行调用,最终生成HTML页面

posted @ 2007-12-18 12:06 船夫 阅读(1892) | 评论 (1)编辑 收藏

Annotation初步了解

今天在看Tapestry代码的时候,突然想了解一下annotation到底是干什么的,有什么好处?花了3个小时的时间,从JDK API开始,大致了解了一下。

annotation实际上就是给一些特定的类和其属性,方法等加上一些注释(annotation),这些注释是以属性name,value进行设置的,这些属性在Annotation Class中以方法的形式存在,如下:
@Documented                //是否需要产生javadoc
@Target(java.lang.annotation.ElementType.METHOD)   //应用目标,这里是应用到field属性上面
@Retention(RetentionPolicy.RUNTIME)   //该策略指明该注释会被加载到jvm中,即在运行时,我们可以得到该注释的内容,另外两个策略,SOURCE, CLASS都不会加载到jvm中
public @interface TestAnnoation {
    String value();   //属性value
    String time();     //属性time
}
以上为自定义的annotation,是应用在成员变量上的,使用该annotation情况如下
public class Test {
    @TestAnnoation(time
="12:30",value="20")
    
public String test(){
          System.out.println("test!");
          return null;
    };
}

可以使用java的反射来进行获取,通过:
Class cls = Class.forName("Test");
cls.isAnnotationPresent(AnnotationClass.
class);//判断是否存在annotation
TestAnnotation ta = (TestAnnotation)cls.getAnnotation(AnnotationClass.class);//获得AnnotationClass实例,后调用这个实例可以获得在AnnotationClass中定义的一些属性
System.out.println(ta.time()); //输出注释time内容
System.out.println(ta.value()); //输出注释value内容

我个人认为annotation的好处是将一些配置直接写在代码上,很直观;以前在使用hibernate的时候,PO对象和对应的mapping xml是分开的,不够直观,若是使用annotation就会很直观的看出这个对象的映射属性以及它的一些特殊属性(如lazy=true)之类的,在JPA中就把这种配置方式换成了annotation。

在JE上有很多关于使用annotation和xml的争论,我认为在小规模使用上可以使用annotation,就像JPA这种,每个PO上面都需要进行配置,即使使用XML也不能简化;而在大规模使用,如spring所维护的一些service的事务配置上避免使用annotation,因为每个service类中都需要配置,而使用AOP根据XML配置可以一下就搞定。

关于ElementType的其他属性:
TYPE(类型), FIELD(属性), METHOD(方法), PARAMETER(参数), CONSTRUCTOR(构造函数),LOCAL_VARIABLE(局部变量), ANNOTATION_TYPE,PACKAGE(包),其中的TYPE(类型)是指可以用在Class,Interface,Enum和 Annotation类型上.

posted @ 2007-12-17 16:33 船夫 阅读(309) | 评论 (1)编辑 收藏

禁食了,肾结石患者还能吃什么?

当肾结石、膀胱结石发生以后,患者在剧烈的疼痛中常向医生讨教:肾脏、尿道里那来的石头呢?手术之后要怎样才能预防它复发呢?
结石的形成,主要原因就是饮食。它是由饮食中可形成结石的有关成分摄入过多引起的。再细一点解释是:
草酸积存过多。体内草酸的大量积存,是导致肾尿结石的 因素之一。如菠菜、豆类、葡萄、可可、茶叶、桔子、番茄、土豆、李子、竹笋等这些人们普遍爱吃的东西,正是含草酸较高的食物。医生通过研究发现:200克 菠菜中,含草酸725.6毫克,如果一人一次将200克菠菜全部吃掉,食后8小时,检查尿中草酸排泄量为20-25毫克,相当于正常人24小时排出的草酸 平均总量。
嘌呤代谢失常。动物内脏、海产食品、花生、豆角、菠菜等,均含有较多的嘌呤成分。嘌呤进入体内后,要进行新陈代谢,它代谢的最终产物是尿酸。尿酸可促使尿中草酸盐沉淀。如果,一次过多地食用了含嘌呤丰富的食物,嘌呤的代谢又失常,草酸盐便在尿中沉积而形成尿结石
脂肪摄取太多。各种动物的肉类,尤其是肥猪肉,都是脂肪多的食品。多吃了体内脂肪必然增高,脂肪会减少肠道中可结合的钙,因而引起对草酸盐的吸收增多,如果一旦出现排泄功能故障,如出汗多、喝水少,尿量少,肾结石很可能就在这种情况下形成。所以,医生们常讲,为了预防得结石病,热天要多喝点水,吃了油水多的食物时,也要多喝点水,以促进排尿畅通,稀释尿液成分,就减少了得结石的危险。
糖分增高。糖是人体的重要养分,要经常适量增补,但一下子增加太多,尤其是乳糖,也会使结石形成创造条件。专家们发现:不论正常人或结石病人,在食用100克蔗糖后,过2小时去检查他们的尿,发现尿中的钙和草酸浓度均上升,若是服用乳糖,它更能促进钙的吸收,更可能导致草酸钙在体内的积存而形成尿结石
蛋白质过量。对肾结石成分进行化验分析,发现结石中的草酸钙占87.5%。这么大比重的草酸钙的来源就是因为蛋白质里除含有草酸的原料——甘氨酸、羟脯氨酸之外,蛋白质还能促进肠道功能对钙的吸收。如果经常过量食用高蛋白质的食物,便使肾脏和尿中的钙、草酸、尿酸的成分普遍增高。如果不能及时有效地通过肾脏功能把多余的钙、草酸、尿酸排出体外,这样,得肾脏结石、输尿管结石症的条件就形成了。当今世界经济发达国家肾结石发病率增高的主要原因就是如此。
从以上几种易形成肾结石的因素来看,要预防肾结石病 的发生,就必须改变只顾单求一种营养和追求营养过甚的观念。这就是说,在人类的日常饮食中,不能因为某种食物好吃、营养价值高,就一味地只顾去吃这种食 物。必须注意食物的搭配,各种食物都适量进食,即使是检查出身体缺乏某种营养素需要某种食物来补充时,也不宜一次大量进食,因为人体的消化、吸收功能是有限的。消化、吸收不了的养分就要通过排泄器官排泄出去,这样也会增加泌尿系统的负担,即便不患肾结石病,也对健康不利。特别是当检查出确认是肾结石症时,在患病期间,要限制病人吃那些易促使结石形成的食物。
结石是尿石症的一种,多在炎热的夏天形成,因为夏天大量出汗,甚至体内脱水,使排尿减少,再加之夏季暴露于阳光下时间长,紫外线照射皮肤有助于体内维生素D和维生素A合成增多,维生素D和维生素A可促进小肠吸收钙离子,尿液中排泄钙增多,尿内结石物质易产生结晶核,从而形成结石。冬季天气寒冷,人的尿量增多,已形成的小结石被尿液冲刷,向下移动,此时引起肾绞痛症状。所以,肾结石常为“夏季形成冬季发病”。

人们的饮食品种是多样的,人体新陈代谢是复杂的,所以肾结石的成分也是多样的。常见结石按成分可分为五种:一草酸钙结石:最为常见,占肾结石的80以上,在酸性或中性尿中形成,发病多为青壮年,以男性多见。二磷酸钙结石:占结石的6-9,在碱性尿中形成,也以男性青壮年多发。三尿酸结石:占结石的6,在酸性尿中形成,当尿PH值大于6.7时结石溶解,以男性多见。四磷酸镁胺结石:占结石的10,在碱性尿中形成,尿PH值小于7.2时结石溶解,以女性多见。五胱氨酸结石:少见,约占结石的1-2,在酸性尿中形成,尿PH值大于7.0时结石溶解。

大量饮水对所有成分尿石都有防治作用。在炎热的夏天,每日尿量少于1200毫升时,尿石生长的危险性显著增大。如能使每日饮水量在2000-4000毫升,这样可维持每日尿量在2000毫升以上。磁化水对防治草酸钙结石更有效,可将全日饮水量分别于晨起、餐间、睡前给予。清晨饮水量可达500-1000毫升。为了保持夜间尿量,睡前饮水500毫升,睡眠中起床排尿后再饮水300-500毫升,余下水分别于餐间饮服。大量饮水可促使小的结石排出,稀释尿液可防止尿石结晶形成,并能延缓结石增长速度。

1985年国外学者Vehlensieck认为,多饮水和饮食疗法可使2/3复发结石病人不再生新结石。下面介绍几种肾结石的饮食疗法。

⑴草酸钙结石:宜低钙及低草酸饮食。少食牛奶及乳制品、豆制品、肉类、动物内脏(如肝、心脏、肾、肠等),还有巧克力、浓茶、芝麻酱、蛋黄、香菇、菠菜、虾皮、萝卜、可可、芹菜、土豆等。近年来发现食物中纤维素可减少尿钙的形成,如麦麸食品中的麦麸面包、米糠也有同样作用,对复发性高钙尿结石有效,维生素B1、维生素B6缺乏使尿草酸增多,应增加富含此类维生素的食物,如谷物、干果、硬果等。

⑵磷酸钙结石及磷酸镁铵结石:其低钙饮食同草酸钙结石相同。在低磷食物中,宜少食肉类、鱼类及骨头汤。

⑶尿结石: 应限制蛋白质的摄入量,每日蛋白质的总摄入量应在48-80克(0.8-1.0克/公斤/日)之间。一般带叶的蔬菜每市斤约含10克蛋白质、瘦肉类每50 克约含蛋白质10克、谷类每市斤含蛋白质35-60克。要增加新鲜蔬菜和水果的食量。蔬菜和水果含维生素B1及维生素C,它们在体内最后代谢产物是碱性 的,尿酸在碱性尿内易于溶解,故有利于治疗。常规治疗:每隔1-2日用一次清凉饮食(生水果、果汁及生菜),至少每周1次清凉饮食。少食或忌用肉类、动物 内脏、肉汤、肉汁、沙丁鱼、蟹、菠菜、浓茶、咖啡,烈性的香料及调味品也宜少用。
现实生活中很多疾病的发生和日常饮食是密切相关的,如果能做到起居有时,饮食有节,甚至大部分癌症也可能避免。现在就肾结石病这一顽症来提醒大家如何用饮食来预防,或使已经患了肾结石者,结石增大的速度减慢,甚至缩小、溶解而排出体外。

(一)多饮白开水 多饮水使尿液得到稀释,钙离子和草酸根的浓度就会降低,形成不了草酸钙结石。研究表明,增加50%的尿量,可使肾结石发病率下降86%。

(二)合理补钙,尤其饮食上补钙 肾结石患者往往“谈钙色变”,错误地认为肾结石的元凶是钙,其实不然,肾结石患者也需要补钙。目前医学界从两个不同的角度来解释,肾结石患者为什么要补钙。

第一是补充钙能与胃肠道中蔬菜含有的草酸结合成不溶性的草酸钙,随粪便排出体外,减少了部分被肠胃吸收和经肾脏排出体外的草酸,从而减少了形成肾结石的几率。

第二是日本学者提出的“酸碱平衡学说”。即血液呈酸性时,结石容易形成。呈碱性时,抑制结石形成。缺钙时血液偏酸性,合理补钙,血液偏碱,这样反而有利于抑制结石形成。

(三)限量摄入糖类 美国科学家最新一项研究结果表明,高糖食品的摄入,可以使患肾结石的机会增加,因此,要注意少吃甜食。

(四)少吃草酸盐含量高的食物 含草酸盐高的食物有番茄、菠菜、草莓、甜菜、巧克力等,过高的草酸盐摄入也是导致肾结石的主要原因之一。

(五)少吃豆制品 大豆食品含草酸盐和磷酸盐都高,能同肾脏中的钙融合,形成结石

(六)睡前慎喝牛奶 睡眠不好的人,睡前喝杯牛奶有助于睡眠。但在睡眠后,尿量减少、浓缩,尿中各种有形物质增加。而饮牛奶后2~3小时,正是钙通过肾脏排泄的高峰。钙通过肾脏在短时间内骤然增多,容易形成结石。因此肾结石患者,睡前就不应喝含钙高的牛奶。

(七)勿过量服用鱼肝油 鱼肝油富含维生素D,有促进肠膜对钙磷吸收的功能,骤然增加尿液中钙磷的排泄,势必产生沉淀,容易形成结石

(八)多食黑木耳 黑木耳中富含多种矿物质和微量元素,能对各种结石产生强烈的化学反应,使结石剥脱、分化、溶解,排出体外。

posted @ 2007-12-17 12:04 船夫 阅读(1386) | 评论 (0)编辑 收藏

XSL取得当前循环的位置

最近在一个项目中用到了XSLT,目的是将返回的XML数据记录通过XSL转换为HTML,在for-each的循环中取得当前记录的位置,通过实践,找到了解决的办法,主要是使用xsl的position函数
1 <xsl:for-each select="QRoleInline-list/QRoleInline">
2 <xsl:if test="not(position() = 1)"><xsl:text>,</xsl:text></xsl:if><xsl:value-of select="@roleName"/>
3 </xsl:for-each>
使用position函数可以取得当前行在循环中的位置,从1开始。上述代码是判断如果位置为第一个, 则需要加逗号。

还有一个函数current()是负责取到当前节点对象的。

posted @ 2007-12-14 11:33 船夫 阅读(514) | 评论 (0)编辑 收藏

走出ClassLoader迷局 --转至sharajava的博克http://www.blogjava.net/sharajava/archive/2006/07/25/59946.html

: 这个问题经常出现在编写框架代码 , 需要动态加载很多类和资源的时候 . 通常当你需要动态加载资源的时候 , 你至少有三个 ClassLoader 可以选择 :

²        系统类加载器或叫作应用类加载器 (system classloader or application classloader)

²        当前类加载器

²        当前线程类加载器

上面的问题指的是最后一种类加载器 . 哪种类加载器是正确的选择呢 ?

第一种选择可以很容易地排除 : 系统类加载器 (system classloader). 这个类加载器处理 -classpath 下的类加载工作 , 可以通过 ClassLoader.getSystemClassLoader() 方法调用 . ClassLoader 下所有的 getSystemXXX() 的静态方法都是通过这个方法定义的 . 在你的代码中 , 你应该尽量少地调用这个方法 , 以其它的类加载器作为代理 . 否则你的代码将只能工作在简单的命令行应用中 , 这个时候系统类加载器 (system classloader) JVM 最后创建的类加载器 . 一但你把代码移到 EJB, Web 应用或 Java Web Start 应用中 , 一定会出问题 .

      所以我们来看第二种选择 : 当前上下文环境下的类加载器 . 根据定义 , 当前类加载器就是你当前方法所属的类的加载器 . 在运行时类之间动态联编 , 及调用 Class.forName,() Class.getResource() 等类似方法时 , 这个类加载器会被隐含地使用 . It is also used by syntactic constructs like X.class class literals.

    线程上下文类型加载器是在Java 2平台上被引入的. 每一个线程都有一个类加载器与之对应(除非这个线程是被本地代码创建的). 这个类加载器是通过Thread.setContextClassLoaser()方法设置的. 如果你不在线程构造后调用这个方法, 这个线程将从它的父线程中继承相应的上下文类加载器. 如果在整个应用中你不做任何特殊设置, 所有的线程将都以系统类加载器(system classloader)作为自己的线程上下文类加载器. 自从WebJ2EE应用服务器使用成熟的类加载器机制来实现诸如JNDI, 线程池, 组件热部署等功能以来, 这种在整个应用中不做任何线程类加载器设置的情况就很少了.

    为什么线程上下文类加载器存在于如此重要的位置呢? 这个概念在J2SE中的引入并不引人注目. 很多开发人员对这一概念迷惑的原因是Sun公司在这方面缺乏适当的指引和文档.

    事实上, 上下文类加载器提供了类加载机制的后门, 这一点也在J2SE中被引入了. 通常, JVM中的所有类加载器被组织成了有继承层次的结构, 每一个类加载器(除了引导JVM的原始类加载器)都有一个父加载器. 每当被请示加载类时, 类加载器都会首先请求其父类加载器, 只有当父类加载器不能加载时, 才会自己进行类加载.

   有时候这种类加载的顺序安排不能正常工作, 通常当必须动态加载应用程序开发人员提供的资源的时候. JNDI为例: 它的内容(J2SE1.3开始)就在rt.jar中的引导类中实现了, 但是这些JNDI核心类需要动态加载由独立厂商实现并部署在应用程序的classpath下的JNDI提供者. 这种情况就要求一个父classloader(本例, 就是引导类加载器)去加载对于它其中一个子classloader(本例, 系统类加载器)可见的类. 这时通常的类加载代理机制不能实现这个要求. 解决的办法(workaround)就是, JNDI核心类使用当前线程上下文的类加载器, 这样, 就基本的类加载代理机制的相反方向建立了一条有效的途径.

    另外, 上面一段可能让你想起一些其它的事情: XML解析Java API(JAXP). 是的, JAXP只是J2SE的扩展进, 它很自然地用当前类加载器来引导解析器的实现. 而当JAXP被加入到J2SE1.4的核心类库中时, 它的类加载也就改成了用当前线程类加载器, JNDI的情况完全类似(也使很多程序员很迷惑). 明白为什么我说来自Sun的指导很缺乏了吧?

   在以上的介绍之后, 我们来看关键问题: 这两种选择(当前类加载器和当前线程类加载器)都不是在所有环境下都适用. 有些人认为当前线程类加载器应该成为新的标准策略. 但是, 如果这样, 当多个线程通过共享数据进行交互的时, 将会呈现出一幅极其复杂的类加载的画面, 除非它们全部使用了同一个上下文的类加载器. 进一步说, 在某些遗留下来的解决方案中, 委派到当前类加载器的方法已经是标准. 比如对Class.forName(String)的直接调用(这也是我为什么推荐尽量避免对这个方法进行调用的原因). 即使你努力去只调用上下文相关的类加载器, 仍然会有一些代码会不由你控制. 这种不受控制的类加载委派机制是混入是很危险的.

    更严重的问题, 某些应用服务器把环境上下文及当前类加载器设置到不同的类加载器实例上, 而这些类加载器有相同的类路径但却没有委派机制中的父子关系. 想想这为什么十分可怕. 要知道类加载器定义并加载的类实例会带有一个JVM内部的ID. 如果当前类加载器加载一个类X的实例, 这个实例调用JNDI查找类Y的实例, 些时的上下文的类加载器也可以定义了加载类Y实例. 这个类Y的定义就与当前类加载器看到的类Y的定义不同. 如果进行强制类型转换, 则产生异常.

   这种混乱的情况还将在Java中存在一段时间. 对于那些需要动态加载资源的J2SEAPI, 我们来猜想它们的类加策略. 例如:

Ø         JNDI 使用线程上下文类加载器

Ø         Class.getResource() Class.forName()使用当前类加载器

Ø         JAXP(J2SE 1.4 及之后)使用线程上下文类加载器

Ø         java.util.ResourceBundle 使用调用者的当前类加载器

Ø         URL protocol handlers specified via java.protocol.handler.pkgs system property are looked up in the bootstrap and system classloaders only

Ø         Java 序列化API默认使用调用者当前的类加载器

这些类及资源的加载策略问题, 肯定是J2SE领域中文档最及说明最缺乏的部分了.

posted @ 2006-07-27 15:23 船夫 阅读(299) | 评论 (0)编辑 收藏

看星星的日子

今天晚上吃完晚饭,往回走的路上,不经意间抬头,看到了很多的星星,我跟同事都停下脚步,抬头分辨哪个是北极星,哪里是北斗七星,聊得非常兴起。
想起来自从到了成都之后,算上这次都只看过两次星星,第一次是大一军训的时候,在华阳看到的,第二次就是今天晚上了。成都市里面不要指望会看到星星,因为浓密的云把所有的星星都遮住了。
昨天听老唐说他看到夜空中有一条“白带”,他说好像是银河,他之前从来都没有看过银河,跟他比起来我真可以算是幸运多了。小时候,到了夏天,家里人和邻居都跑到院子里面纳凉,我就躺在母亲的怀里面,边享受母亲扇子带来的凉爽,边抬头看星星,东北的星空真的是非常清晰,那时候,母亲给我讲哪个是银河,哪个是牛郎织女,哪个是勺子星(北斗七星),还给我讲牛郎织女的故事,说一到了七月初七就会下雨,那是因为牛郎和织女相会的泪水,还说从来没说过谎的小孩子趴在黄瓜架下面可以听到他们的哭声,想想现在认识的那几颗星星都是那个时候记下来的,书本上学的好像都不知道被我丢到哪里去了。那时候看到的星空现在回想起来真的是非常漂亮,就像冰心在繁星中描述的一样。
已经很多年没在家里面过夏天了,过年的时候倒是有回去,但是天气太冷,实在没那种兴致去看星星。
长大了,反而觉得快乐只存在于回忆中了,这是成长的代价吗?

posted @ 2006-07-25 23:53 船夫 阅读(250) | 评论 (0)编辑 收藏

惰性已经在充分的滋长

已经封闭开发了近三个月了,由刚开始的热情高涨到现在的热情全无,我已经逐渐被自己的惰性所吞噬,已经快慢慢的丢失了真正的自我。

经过了这么一段时间,曾经对新技术非常感兴趣的我已经完全失去了这种热情。

知耻而后勇,我要克服自己的这种情绪,重新开始,用崭新的眼光去对待每一天

posted @ 2006-07-25 23:22 船夫 阅读(209) | 评论 (0)编辑 收藏

项目中遇到的一个Spring事务管理的问题

今天从CVS上checkout项目的时候,出现了一个问题,我以前写的模块功能本来是好的,但是checkout之后就出了问题,我想一定是配置文件更新出错了,努力寻找,发现没有问题.后来经同事说他更改了一个方法,而我的代码中有对那个方法的调用,终于知道了问题的所在.
程序中抛出的异常是
java.lang.IllegalStateException: No value for key [org.hibernate.impl.SessionFactoryImpl@7a3d45f0] bound to thread [Servlet.Engine.Transports : 0]
我发现是在我spring的sevice方法中调用了他的方法,他的方法又调用了另一个service方法,导致出现了这个问题.

这个问题只要把他的那个方法修改一下,或者从我的service方法中移出就可以解决.

我想spring中肯定应该有些配置能使两个service方法处于同一个事务中,但是我还没找到.希望知道的高手能提点一下,谢谢

posted @ 2006-07-24 18:40 船夫 阅读(644) | 评论 (0)编辑 收藏

在WSAD 5.1中使用log4j遇到的问题

使用log4j作为日志输出工具,设置根级别为warn,然后分别设置了hibernate和spring等的级别为debug,自己项目的级别也设置为debug,但是很奇怪的事情出现了:
我启动wasd的测试服务器,打出来的日志只有我本项目的debug级以上的信息,spring和hibernate的都打不出来;
我使用main函数运行我项目中的一个方法,所有的debug信息,spring和hibernate以及我本项目的debug信息一样都没少。
我的配置是绝对没有问题的,我实在想不出来怎么会出现这种问题,见鬼了,哪位高手遇到过这种情况,告知一下解决方法,谢谢

posted @ 2006-07-21 01:23 船夫 阅读(542) | 评论 (4)编辑 收藏

好久没有思考过什么了,整个大脑都仿佛已经失去了这个能力,每天忙着要么是做项目,要么就是忙着发呆,发呆自己能想些什么,做些什么,脑袋真的已经生锈了。
整个人再也没有高中时候的那种反应,看来这个大学读的是亏了,直到现在还改变不了这种坏习惯。其实我很清楚,我这样对自己说完全是找个借口,这样才能使自己感到没有那么的空虚,少些对自己的自责。不过我发现,很久以来,都没有那种自责的心理了,不会在为自己的懒散感到自责,真的是很奇怪,在高中的时候,中午或周末多玩儿了一会儿,或是做错了一道不该做错的题,都会感到非常的愧疚,为此而一直自责。现在长大了,每天充斥在脑子里面的都是,怎样才能赚钱,学什么才能让自己更加有发展,思考的越来越现实,反而发现自己的动力越来越不足,天哪,我是怎么了?
买房子,结婚?现实围绕在我的身边,把我压得好紧,女友说我脾气太好,没有男子气概?难道我对她发脾气才是好的吗?两地分居,为了生活出去奔波,希望能赚回来一栋房子,难道我愿意吗?她爸和她妈对我的印象也不是很好,我知道我这个人太笨了,不会说话,不会讨别人喜欢,啊~~~~~~~~~~~我实在是受不了了,我已经对自己失望透顶了,谁能告诉我这个时候应该能做什么?????
我要改变这一切,我要改变自己,我要提高自己的能力,我要改变他人对我的看法,我要做一个让所有人都满意的人,我他妈的是为了什么活得这么累啊,爱情,不是应该两个人之间事吗?干嘛有那么多外在因素要影响我呢?
25岁,这个世界让我变得衰老~~~

posted @ 2006-07-21 01:14 船夫 阅读(188) | 评论 (0)编辑 收藏

表的外键约束[ZT]

1。创建测试表
SQL> create table lesson(lesson_name varchar2(20), classroom varchar2(10));

表已创建。

SQL> create table teacher(name varchar2(20),lesson_name varchar2(20));

表已创建。

SQL> alter table lesson add constraint pk_lesson primary key(lesson_name);

表已更改。

SQL> alter table teacher add constraint fk_lessonname foreign key(lesson_name)
2 references lesson(lesson_name);

表已更改。


2。插入测试数据
SQL> insert into lesson values('english','class 1');

已创建 1 行。

SQL> insert into lesson values('music','class 2');

已创建 1 行。


3。测试有外键的字段是否可以为空
SQL> insert into teacher values('wang','hello');
insert into teacher values('wang','hello')
*
ERROR 位于第 1 行:
ORA-02291: 违反完整约束条件 (SYSTEM.FK_LESSONNAME) - 未找到父项关键字

SQL> insert into teacher values('wang','music');

已创建 1 行。

SQL> insert into teacher values('wang',null);

已创建 1 行。


结论:有外键约束的字段可以为空。如果不为空的话,则一定要满足外键的约束关系

posted @ 2006-03-16 15:44 船夫 阅读(316) | 评论 (0)编辑 收藏

outer和left outer join有什么区别??

outer和left outer join有什么区别??

使用关系代数合并数据
1 关系代数
合并数据集合的理论基础是关系代数,它是由E.F.Codd于1970年提出的。
在关系代数的形式化语言中:
        用表、或者数据集合表示关系或者实体。
        用行表示元组。
        用列表示属性。
关系代数包含以下8个关系运算符
        选取――返回满足指定条件的行。
        投影――从数据集合中返回指定的列。
        笛卡尔积――是关系的乘法,它将分别来自两个数据集合中的行以所有可能的方式进行组合。
        并――关系的加法和减法,它可以在行的方向上合并两个表中的数据,就像把一个表垒在另一个表之上一样。
        交――返回两个数据集合所共有的行。
        差――返回只属于一个数据集合的行。
        连接――在水平方向上合并两个表,其方法是:将两个表中在共同数据项上相互匹配的那些行合并起来。
        除――返回两个数据集之间的精确匹配。
此外,作为一种实现现代关系代数运算的方法,SQL还提供了:
        子查询――类似于连接,但更灵活;在外部查询中,方式可以使用表达式、列表或者数据集合的地方都可以使用子查询的结果。
本章将主要讲述多种类型的连接、简单的和相关的子查询、几种类型的并、关系除以及其他的内容。
2 使用连接
2.1 连接类型
在关系代数中,连接运算是由一个笛卡尔积运算和一个选取运算构成的。首先用笛卡尔积完成对两个数据集合的乘运算,然后对生成的结果集合进行选取运算,确保只把分别来自两个数据集合并且具有重叠部分的行合并在一起。连接的全部意义在于在水平方向上合并两个数据集合(通常是表),并产生一个新的结果集合,其方法是将一个数据源中的行于另一个数据源中和它匹配的行组合成一个新元组。
SQL提供了多种类型的连接方式,它们之间的区别在于:从相互交叠的不同数据集合中选择用于连接的行时所采用的方法不同。
连接类型        定义
内连接        只连接匹配的行
左外连接        包含左边表的全部行(不管右边的表中是否存在与它们匹配的行),以及右边表中全部匹配的行
右外连接        包含右边表的全部行(不管左边的表中是否存在与它们匹配的行),以及左边表中全部匹配的行
全外连接        包含左、右两个表的全部行,不管另外一边的表中是否存在与它们匹配的行。
(H)(theta)连接        使用等值以外的条件来匹配左、右两个表中的行
交叉连接        生成笛卡尔积-它不使用任何匹配或者选取条件,而是直接将一个数据源中的每个行与另一个数据源的每个行都一一匹配
在INFORMIX中连接表的查询
如果FROM子句指定了多于一个表引用,则查询会连接来自多个表的行。连接条件指定各列之间(每个表至少一列)进行连接的关系。因为正在比较连接条件中的列,所以它们必须具有一致的数据类型。
SELECT语句的FROM子句可以指定以下几种类型的连接
FROM子句关键字        相应的结果集
CROSS JOIN        笛卡尔乘积(所有可能的行对)
INNER JOIN        仅对满足连接条件的CROSS中的列
LEFT OUTER JOIN        一个表满足条件的行,和另一个表的所有行
RIGHT OUTER JOIN        与LEFT相同,但两个表的角色互换
FULL OUTER JOIN        LEFT OUTER 和 RIGHT OUTER中所有行的超集

2.2 内连接(Inner Join)
内连接是最常见的一种连接,它页被称为普通连接,而E.FCodd最早称之为自然连接。
下面是ANSI SQL-92标准
select *
from  t_institution i
inner join t_teller t
on i.inst_no = t.inst_no
where i.inst_no = "5801"
其中inner可以省略。
等价于早期的连接语法
select *
from t_institution i, t_teller t
where i.inst_no = t.inst_no
and i.inst_no = "5801"

2.3 外连接
2.3.1        左外连接(Left Outer Jion)
select *
from  t_institution i
left outer join t_teller t
on i.inst_no = t.inst_no
其中outer可以省略。
2.3.2        右外连接(Rigt Outer Jion)
select *
from  t_institution i
right outer join t_teller t
on i.inst_no = t.inst_no
2.3.3        全外连接(Full Outer)
全外连接返回参与连接的两个数据集合中的全部数据,无论它们是否具有与之相匹配的行。在功能上,它等价于对这两个数据集合分别进行左外连接和右外连接,然后再使用消去重复行的并操作将上述两个结果集合并为一个结果集。
在现实生活中,参照完整性约束可以减少对于全外连接的使用,一般情况下左外连接就足够了。在数据库中没有利用清晰、规范的约束来防范错误数据情况下,全外连接就变得非常有用了,你可以使用它来清理数据库中的数据。
select *
from  t_institution i
full outer join t_teller t
on i.inst_no = t.inst_no
2.3.4        外连接与条件配合使用
当在内连接查询中加入条件是,无论是将它加入到join子句,还是加入到where子句,其效果是完全一样的,但对于外连接情况就不同了。当把条件加入到join子句时,SQL Server、Informix会返回外连接表的全部行,然后使用指定的条件返回第二个表的行。如果将条件放到where子句中,SQL Server将会首先进行连接操作,然后使用where子句对连接后的行进行筛选。下面的两个查询展示了条件放置位子对执行结果的影响:
条件在join子句
select *
from  t_institution i
left outer join t_teller t
on i.inst_no = t.inst_no
and i.inst_no = “5801”
结果是:
inst_no    inst_name            inst_no    teller_no  teller_name
5801       天河区               5801       0001       tom
5801       天河区               5801       0002       david
5802       越秀区
5803       白云区
条件在where子句
select *
from  t_institution i
left outer join t_teller t
on i.inst_no = t.inst_no
where i.inst_no = “5801”
结果是:
inst_no    inst_name            inst_no    teller_no  teller_name
5801       天河区               5801       0001       tom
5801       天河区               5801       0002       david

2.4 自身连接
自身连接是指同一个表自己与自己进行连接。这种一元连接通常用于从自反关系(也称作递归关系)中抽取数据。例如人力资源数据库中雇员与老板的关系。
下面例子是在机构表中查找本机构和上级机构的信息。
select s.inst_no superior_inst, s.inst_name sup_inst_name, i.inst_no, i.inst_name
from t_institution i
join t_institution s
on i.superior_inst = s.inst_no

结果是:
superior_inst sup_inst_name        inst_no    inst_name
800           广州市               5801       天河区
800           广州市               5802       越秀区
800           广州市               5803       白云区

2.5 交叉(无限制) 连接
交叉连接用于对两个源表进行纯关系代数的乘运算。它不使用连接条件来限制结果集合,而是将分别来自两个数据源中的行以所有可能的方式进行组合。数据集合中一的每个行都要与数据集合二中的每一个行分别组成一个新的行。例如,如果第一个数据源中有5个行,而第二个数据源中有4个行,那么在它们之间进行交叉连接就会产生20个行。人们将这种类型的结果集称为笛卡尔乘积。
大多数交叉连接都是由于错误操作而造成的;但是它们却非常适合向数据库中填充例子数据,或者预先创建一些空行以便为程序执行期间所要填充的数据保留空间。
select *
from  t_institution i
cross join t_teller t
在交叉连接中没有on条件子句

3 APPENDIX
3.1 A 参考资料与资源
        《Microsoft SQL Server 2000 Bile》Paul Nielsen
        Paul Nielsen的Web站点
www.isnotnull.com
3.2 注文章所有SQL在IBM Informix Dynamic Server Version 9.40.TC2E1测试通过

posted @ 2006-03-06 13:02 船夫 阅读(1633) | 评论 (0)编辑 收藏