﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-疯狂-随笔分类-方法论</title><link>http://www.blogjava.net/freeman1984/category/46503.html</link><description>STANDING ON THE SHOULDERS OF GIANTS
</description><language>zh-cn</language><lastBuildDate>Mon, 05 Jun 2017 06:30:06 GMT</lastBuildDate><pubDate>Mon, 05 Jun 2017 06:30:06 GMT</pubDate><ttl>60</ttl><item><title>JAVA Thread Dump 分析综述</title><link>http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 14 Dec 2015 10:04:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/428645.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/428645.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/428645.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载自:http://blog.csdn.net/rachel_luo/article/details/8920596最近在做性能测试，需要对线程堆栈进行分析，在网上收集了一些资料，学习完后，将相关知识整理在一起，输出文章如下。一、Thread Dump介绍1.1什么是Thread Dump？Thread Dump是非常有用的诊断Java应用问题的工具。每一个Java虚拟机都有及时生成所有线程在某...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/428645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2015-12-14 18:04 <a href="http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 索引字段包含date类型，使用spring jdbc更新时不走索引，而是走table access full的问题</title><link>http://www.blogjava.net/freeman1984/archive/2015/11/15/428197.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sat, 14 Nov 2015 16:04:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2015/11/15/428197.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/428197.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2015/11/15/428197.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/428197.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/428197.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: oracle 索引字段包含date类型，使用spring jdbc更新时不走索引，而是走table access full的问题&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2015/11/15/428197.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/428197.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2015-11-15 00:04 <a href="http://www.blogjava.net/freeman1984/archive/2015/11/15/428197.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于java RMI在多网卡下(或者启动360，百度，腾讯等wifi共享下)无法连接问题(java.rmi.ConnectException: Connection refused to host: xx)</title><link>http://www.blogjava.net/freeman1984/archive/2014/12/05/421085.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 05 Dec 2014 06:08:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2014/12/05/421085.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/421085.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2014/12/05/421085.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/421085.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/421085.html</trackback:ping><description><![CDATA[<strong>场景</strong>：java RMI 在服务端者启动360 wifi共享，报错java.rmi.ConnectException: Connection refused to host: xx。<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;也就是服务端在调用时使用了wifi共享网卡的地址。此地址在RMI客户端pc上无法ping通。（因为没有连接此wifi。当然RMI客户端pc如果连接此wifi是不会报错的）。<br /><strong>想关资料：<br /><br /></strong>http://docs.huihoo.com/java/rmi/whitepage/index.html<strong><br /></strong>比较全的解释RMI的英文资料：http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/faq.html#netunknownhost<br /><div>http://www.blogjava.net/shaolijun/archive/2007/05/22/119213.html</div><br />
<strong>测试代码</strong>：<br /><br />(一)服务端：<br /><ul><li><span style="font-size: 10pt;">服务接口</span></li></ul>

<div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">import</span>&nbsp;java.rmi.Remote;<br />
<span style="color: #0000FF; ">import</span>&nbsp;java.rmi.RemoteException;<br />
<span style="color: #008000; ">/**</span><span style="color: #008000; "><br />
&nbsp;*&nbsp;rmi&nbsp;remote&nbsp;接口<br />
&nbsp;*&nbsp;</span><span style="color: #808080; ">@author</span><span style="color: #008000; ">&nbsp;joe<br />
&nbsp;*&nbsp;@2014-12-5&nbsp;@上午11:49:10<br />
&nbsp;</span><span style="color: #008000; ">*/</span><br />
<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">interface</span>&nbsp;RmiInterface&nbsp;<span style="color: #0000FF; ">extends</span>&nbsp;Remote{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;say(String&nbsp;name)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;RemoteException;<br />
<br />
}</div><ul><li><span style="font-size: 10pt;">接口实现</span></li></ul>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">import</span>&nbsp;java.rmi.RemoteException;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.rmi.server.UnicastRemoteObject;<br /><br /><br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;RmiServer&nbsp;<span style="color: #0000FF; ">extends</span>&nbsp;UnicastRemoteObject&nbsp;<span style="color: #0000FF; ">implements</span>&nbsp;RmiInterface{<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;serialVersionUID&nbsp;=&nbsp;1L;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">protected</span>&nbsp;RmiServer()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;RemoteException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">super</span>();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;say(String&nbsp;name)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;RemoteException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;"hello，"+name;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><ul><li><span style="font-size: 10pt;">发布服务</span></li></ul><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;MalformedURLException,&nbsp;RemoteException,&nbsp;AlreadyBoundException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RmiServer&nbsp;server=<span style="color: #0000FF; ">new</span>&nbsp;RmiServer();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocateRegistry.createRegistry(8808);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Naming.rebind("//10.10.XX.XX:8808/SAMPLE-SERVER",&nbsp;server);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</div><br />(二)客户端 调用服务：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;Exception&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RmiInterface&nbsp;server=(RmiInterface)&nbsp;Naming.lookup("//10.10.116.XX:8808/SAMPLE-SERVER");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(server.say("张三"));<br />&nbsp;&nbsp;&nbsp;&nbsp;}</div><br />此时报错，java.rmi.ConnectException: Connection refused to host: 192.168.23.X。<br /><br />RMI的调用原理基本如下：<br /><img src="http://www.blogjava.net/images/blogjava_net/freeman1984/rmi1.png" width="1341" height="365" alt="" /><br /><strong>大致翻译如下</strong>：首先客户端必须通过Naming.lookup得到服务端服务的一个指针或者叫指针，一旦拥有的这个应用，客户端将使用服务的引用里面包含的主机名(ip)和端口来访问服务。<br />&nbsp; &nbsp; 也就是说：虽然我们就服务端的IP和端口去<span style="font-size: 13px; background-color: #eeeeee;">Naming.lookup("//10.10.116.XX:8808/SAMPLE-SERVER");</span>，但是服务端返回的服务的引用里面包含的ip并不是lookup时的ip。<br />官方说法：<br /><strong><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">【In many&nbsp;</span><a href="http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/faq.html#nethostname" style="font-family: Simsun; font-size: medium; line-height: normal;">versions of the JDK</a><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">&nbsp;(all versions of the JDK except in&nbsp;</span><a href="http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/faq.html#nethostname.1.1" style="font-family: Simsun; font-size: medium; line-height: normal;">v1.1</a><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">&nbsp;and the&nbsp;</span><a href="http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/faq.html#nethostname.latestReleases" style="font-family: Simsun; font-size: medium; line-height: normal;">latest releases)</a><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">, Java RMI may default to using an unresolvable server hostname (for example: unqualified names, Windows Internet Naming Service (WINS) names, or unqualified DHCP names). When a Java RMI client invokes a remote method using a reference that contains an unresolvable server hostname, the client will throw an&nbsp;</span><code style="line-height: normal;">UnknownHostException</code><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">.】</span></strong><p style="font-family: Simsun; font-size: medium; line-height: normal;">In order to generate functional remote references, Java RMI servers must be able to supply a fully qualified hostname or IP address that is resolvable from all Java RMI clients (an example of a fully qualified hostname is&nbsp;<samp>foo.bar.com</samp>). If a Java RMI program provides a remote callback operation, then that program serves a Java RMI object and consequently, must be able to determine a resolvable hostname to use as its server hostname in the remote references it passes to Java RMI clients. VMs that make calls to applets that serve remote objects may throw<code>UnknownHostException</code>s because the applet has failed to provide a usable server hostname.</p><p style="font-family: Simsun; font-size: medium; line-height: normal;">If your Java RMI application throws an&nbsp;<code>UnknownHostException</code>, you can look at the resulting stack trace to see if the hostname that the client is using to contact its remote server is incorrect or not fully qualified.【&nbsp;<strong>If necessary, you can set the&nbsp;<code>java.rmi.server.hostname</code>&nbsp;property on the server to the correct IP address or hostname of the server machine and Java RMI will use this property's value to generate remote references to the server.】</strong></p>解决办法就是在服务端发布注册服务的之前设置：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->System.setProperty("java.rmi.server.hostname",&nbsp;指定IP);</div><br />对应到本文例子就是：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;MalformedURLException,&nbsp;RemoteException,&nbsp;AlreadyBoundException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RmiServer&nbsp;server=<span style="color: #0000FF; ">new</span>&nbsp;RmiServer();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>System.setProperty("java.rmi.server.hostname",&nbsp;指定IP);</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocateRegistry.createRegistry(8808);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Naming.rebind("//10.10.116.74:8808/SAMPLE-SERVER",&nbsp;server);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</div><br />但是此时还是报相同的错没法访问，百思不得其解，原来<span style="font-family: Simsun; font-size: medium; line-height: normal;"><code><strong>java.rmi.server.hostname</strong>的设置必须在服务对象创建之前。<br /></code></span><div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;MalformedURLException,&nbsp;RemoteException,&nbsp;AlreadyBoundException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>&nbsp;System.setProperty("java.rmi.server.hostname",&nbsp;指定IP);</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RmiServer&nbsp;server=<span style="color: #0000FF; ">new</span>&nbsp;RmiServer();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocateRegistry.createRegistry(8808);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Naming.rebind("//10.10.116.74:8808/SAMPLE-SERVER",&nbsp;server);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</div><div>为什么呢：<br />&nbsp; &nbsp;&nbsp;<span style="font-size: 13px; background-color: #eeeeee;">RmiServer&nbsp;</span>这个实现类使用了UnicastRemoteObject去联接RMI系统。在我们的例子中，我们是直接的从UnicastRemoteObject这个类上继承的，事实上并不一定要这样做，当然也可以不是从UnicastRmeoteObject上继承，那必须使用它的exportObject()方法去联接到RMI。如果一个类继承自UnicastRemoteObject，那么它必须提供一个构造函数并且声明抛出一个RemoteException对象。当这个构造函数调用了super()，它久激活UnicastRemoteObject中的代码完成RMI的连接和远程对象的初始化。而此时应该已经决定了使用哪个hostname来实例化远程对象。因此必须在服务对象创建之前指定绑定的hostname。<br /><br />~~~完。</div><img src ="http://www.blogjava.net/freeman1984/aggbug/421085.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2014-12-05 14:08 <a href="http://www.blogjava.net/freeman1984/archive/2014/12/05/421085.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>dbcp重连(转) </title><link>http://www.blogjava.net/freeman1984/archive/2013/06/06/400263.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 06 Jun 2013 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2013/06/06/400263.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/400263.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2013/06/06/400263.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/400263.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/400263.html</trackback:ping><description><![CDATA[<p>转自：<a href="http://lc87624.iteye.com/blog/1734089">http://lc87624.iteye.com/blog/1734089</a></p>
<p>&nbsp;</p>
<div id="blog_content" class="blog_content">使用数据库连接池时，免不了会遇到断网、数据库挂掉等异常状况，当网络或数据库恢复时，若无法恢复连接池中的连接，那必然会是一场灾难。 <br /><br />关于dbcp的自动重连配置，网上相关的资料也不少，通过以下资料，并对照官方文档中的参数说明，大致能了解各项配置的含义，我就不冗诉了，本文的目的主要是对问题排查的经过做个简单的记录。 <br />参考资料： <br />
<ul><li><a href="http://agapple.iteye.com/blog/791943" target="_blank">解读dbcp自动重连那些事</a></li><li><a href="http://commons.apache.org/dbcp/configuration.html" target="_blank">官方文档</a> </li></ul><br />测试环境： <br />
<ul><li>dbcp版本&#8212;&#8212;1.4</li><li>数据库&#8212;&#8212;postgresSQL 9.10（简称pg）</li><li>本地(以下称为client)操作系统及数据库服务器(以下称为server)操作系统均为linux</li><li>server位于内网环境，client需要通过vpn或网线直连内网才能访问数据库 </li></ul><br /><strong>首先模拟的是断网的情况</strong> <br />在本地测试dbcp的重连配置时，发现断网后，连接池无法重建连接，分别试过testOnBorrow和testWhileIdle两种validate方式，都没能解决，现象如下： <br />1. 正常启动应用，在server端通过"select * from pg_stat_activity"查看连接数，会有initialSize个来自client的IDLE连接。&#8212;&#8212;正常 <br />2. 在client端执行各种查询操作，连接数保持不变，且在server端的db log中能看到validate query。&#8212;&#8212;正常 <br />3. 手动切断vpn，client与server断开，查询无法返回结果；然后重连，再次查看连接数，连接数仍保持不变，且连接的创建时间为断网前，即是说连接池认为之前的连接仍然有效，没有销毁旧连接&amp;创建新连接。 <br />4. 此时在应用中执行各种查询操作，均无响应，等待一段时间后（分钟级），超时抛出异常： <br />Caused by: org.postgresql.util.PSQLException: An I/O error occured while sending to the backend. <br />Caused by: java.net.SocketException: Connection timed out. <br />5. 继续通过"select * from pg_stat_activity"查看连接数，隔一段时间后，连接消失。 <br /><br /><strong>问题：</strong>断网后，仍留在线程池内的连接是否有效？若有效，为什么网络恢复后查询无响应？若无效，为何线程池没有发现并重新创建有效连接？ <br /><strong>排查过程：</strong> <br />1.重连vpn后，通过netstat查看client至server的连接 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://lc87624.iteye.com/blog/1734089#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span>sudo&nbsp;netstat&nbsp;-antop&nbsp;|&nbsp;grep&nbsp;:</span><span class="number"><font color="#c00000">5432</font></span><span>&nbsp;&nbsp;|&nbsp;grep&nbsp;java&nbsp;&nbsp;</span></li></ol></div><em>注：5432为pg端口，grep java是为了过滤client上的其他形式的连接。</em> <br />发现连接数和在server端看到的连接数一致，且均为ESTABLISH状态。 <br />2. 但在client上执行查询时，通过tcpdump查看client发往server的tcp请求，并无任何请求产生。 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://lc87624.iteye.com/blog/1734089#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-j"><li><span>sudo&nbsp;tcpdump&nbsp;-s&nbsp;</span><span class="number"><font color="#c00000">65535</font></span><span>&nbsp;-X&nbsp;-i&nbsp;eth0&nbsp;host&nbsp;xxx.xxx.xxx&nbsp;&nbsp;</span></li></ol></div>可见当前线程池中的连接实际上已经失效了，但dbcp仍认为它是有效的，因此仍在尝试用旧连接访问数据库，直至网络超时。 <br /><br />于是，开始怀疑是vpn的问题，将client接上网线直连内网后，再次重试上述步骤，只是把断网的方式由切断vpn换成了拔网线，发现这次使用断网前的连接能够正常访问数据库，于是断定是vpn的问题，猜测是重连vpn后，虽然client端ip没有变，但路由的路径已经变了，之前的连接无法复用，但dbcp并不知道。对网络细节不是太熟悉，就不多加揣测了。 <br /><br /><strong>接下来模拟数据库断开client连接的情况</strong> <br />由于pg采用的是进程模型，与数据库建立的每一个连接都是单独的一个进程，故尝试采用kill进程的方式模拟数据库断开连接。 <br />预期的结果是：kill掉一个连接进程后，dbcp通过validate query发现该连接失效，将销毁该连接并重新创建新连接。 <br />但实际情况确是：kill掉一个连接后，所有连接全部被销毁。 <br /><strong>问题：</strong>究竟是数据库还是dbcp销毁了所有连接? <br /><strong>排查过程：</strong> <br />熟悉pg的同事认为pg之所以采用进程模型，就是为了避免连接之间的影响，因此不可能发生kill一个连接，其他连接也被销毁的情况。在这个理论前提下，问题就变得很诡异，因为dbcp的validate肯定是针对一个连接的，也不可能会在validate一个连接失效的情况下销毁所有连接，于是越想越偏，甚至开始怀疑是pg的jdbc driver有问题，最终放弃了深究。 <br />但我总觉得有点不太对劲，于是推翻之前的前提，开始怀疑是pg销毁了所有连接。于是，在使用连接池的应用之外，通过pg的数据库客户端psql连接db，这就建立了一个与dbcp无关的连接，接着继续在server端kill了一个连接池中的连接，继而发现psql创建的连接也被销毁了，这就能确定是pg在销毁连接，因为dbcp不可能控制自身范围之外的连接。 <br />后来才知道，pg之所以会这么做，是因为我们kill连接时使用的是kill -9（简称9杀），9杀太过粗暴，pg会重启很多内部进程，以保证所有进程正常，之前的连接也将会丢失，换用普通的kill命令，则不会发生以上情况。可见9杀很多情况下是十分危险的，试想一个线上db，若是9杀一个连接，后果不堪设想。。。 <br /><br /><strong>总结</strong> <br />说是dbcp问题排查，但大家可以看到最终问题的根源都跟dbcp没有什么关系。实际工作中的很多问题，关联的因素众多，需要有各方面的知识储备才能找到真正问题根源，否则就会把问题归结到一个自己不太了解的领域。 <br />另外，看到<a href="http://agapple.iteye.com/blog/772507" target="_blank">dbcp基本配置和重连配置</a>这篇文章中对连接池重连有两句不错的总结，引用一下： <br />
<div class="quote_title">引用</div>
<div class="quote_div">1. 数据库意外重启后，原先的数据库连接池能自动废弃老的无用的链接，建立新的数据库链接 <br />2. 网络异常中断后，原先的建立的tcp链接，应该能进行自动切换</div><br /><br />最后附上测试使用的dbcp配置。 <br />testOnBorrow配置： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Xml代码 <a title="复制代码" href="http://lc87624.iteye.com/blog/1734089#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-xml"><li><span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">bean</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">id</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"dataSource"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">class</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"org.apache.commons.dbcp.BasicDataSource"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">destroy-method</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"close"</font></span><span class="tag"><strong><font color="#006699">&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"driverClassName"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"${jdbc.driver}"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"url"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"${jdbc.url}"</font></span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"username"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"${jdbc.user}"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"password"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"${jdbc.passwd}"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"removeAbandoned"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"true"</font></span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"initialSize"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"10"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"maxIdle"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"10"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"minIdle"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"10"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"maxActive"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"30"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"maxWait"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"30000"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"testWhileIdle"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"false"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"testOnBorrow"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"true"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"testOnReturn"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"false"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"validationQuery"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"select&nbsp;1"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comments">&lt;!--&nbsp;&lt;property&nbsp;name=&nbsp;"validationQueryTimeout"&nbsp;value="1"&nbsp;/&gt;&nbsp;配置已失效--&gt;</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span></font></strong><span>&nbsp;&nbsp;</span></span></li></ol></div>testWhileIdle配置： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Xml代码 <a title="复制代码" href="http://lc87624.iteye.com/blog/1734089#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-xml"><li><span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">bean</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">id</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"dataSource"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">class</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"org.apache.commons.dbcp.BasicDataSource"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">destroy-method</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"close"</font></span><span class="tag"><strong><font color="#006699">&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"driverClassName"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"${jdbc.driver}"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"url"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"${jdbc.url}"</font></span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"username"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"${jdbc.user}"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"password"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"${jdbc.passwd}"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"removeAbandoned"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"true"</font></span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"initialSize"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"10"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"maxIdle"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"10"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"minIdle"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"10"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"maxActive"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"30"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"maxWait"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"30000"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"testWhileIdle"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"true"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"testOnBorrow"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"false"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"testOnReturn"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"false"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"validationQuery"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"select&nbsp;1"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comments">&lt;!--&nbsp;&lt;property&nbsp;name=&nbsp;"validationQueryTimeout"&nbsp;value="1"&nbsp;/&gt;&nbsp;配置已失效--&gt;</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"timeBetweenEvictionRunsMillis"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"30000"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=&nbsp;</span><span class="attribute-value"><font color="#0000ff">"numTestsPerEvictionRun"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"30"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;</span><span class="tag-name">property</span></font></strong><span>&nbsp;</span><span class="attribute"><font color="#ff0000">name</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"minEvictableIdleTimeMillis"</font></span><span>&nbsp;</span><span class="attribute"><font color="#ff0000">value</font></span><span>=</span><span class="attribute-value"><font color="#0000ff">"1800000"</font></span><span>&nbsp;</span><span class="tag"><strong><font color="#006699">/&gt;</font></strong></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><strong><font color="#006699"><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span></font></strong><span>&nbsp;&nbsp;</span></span></li></ol></div><pre style="display: none" class="xml" title="dbcp重连问题排查" pre_index="3" source_url="http://lc87624.iteye.com/blog/1734089" codeable_type="Blog" codeable_id="1734089" name="code">&nbsp;</pre>注：testOnBorrow只会发现当前连接失效，再创建一个连接供当前查询使用，而testWhileIdle会定时校验numTestsPerEvictionRun个连接，只要发现连接失效，就将其移除再重新创建。 </div>
<p>&nbsp;</p><img src ="http://www.blogjava.net/freeman1984/aggbug/400263.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2013-06-06 09:38 <a href="http://www.blogjava.net/freeman1984/archive/2013/06/06/400263.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>URL最大长度限制(转)</title><link>http://www.blogjava.net/freeman1984/archive/2013/05/30/399942.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 30 May 2013 01:29:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2013/05/30/399942.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/399942.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2013/05/30/399942.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/399942.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/399942.html</trackback:ping><description><![CDATA[<div id="article_content" class="article_content">
<p class="entry">转自：<a href="http://blog.csdn.net/jinhill/article/details/3961881">http://blog.csdn.net/jinhill/article/details/3961881</a></p>
<div class="entry">
<ol><li>URL不能大于255bytes的说法确实存在，在<a title="RFC2616" href="http://www.w3.org/Protocols/rfc2616/rfc2616.html" target="_blank">RFC2616</a>中提到：<br />
<blockquote>
<p>The HTTP protocol does not place any a priori limit on the length of a URI. Servers MUST be able to handle the URI of any resource they serve, and SHOULD be able to handle URIs of unbounded length if they provide GET-based forms that could generate such URIs. A server SHOULD return 414 (Request-URI Too Long) status if a URI is longer than the server can handle (see section 10.4.15).</p>
<p>Note: <span style="color: #ff0000">Servers ought to be cautious about depending on URI lengths above 255 bytes, because some older client or proxy implementations might not properly support these lengths.</span></p></blockquote></li><li>从上一点也可以看出，255bytes的说法也是为了兼容性考虑。实际上现代浏览器的限制如下：<br />
<blockquote>
<p><strong>Microsoft Internet Explorer (Browser)</strong><br />Microsoft states that the maximum length of a URL in Internet Explorer is <a title="Maximum URL length is 2,083 characters in Internet Explorer" href="http://support.microsoft.com/kb/q208427/" target="_blank">2,083 characters</a>, with no more than 2,048 characters in the path portion of the URL. In my tests, attempts to use URLs longer than this produced a clear error message in Internet Explorer.<br /><strong>Firefox (Browser)</strong><br />After 65,536 characters, the location bar no longer displays the URL in Windows Firefox 1.5.x. However, longer URLs will work. I stopped testing after 100,000 characters.<br /><strong>Safari (Browser)</strong><br />At least 80,000 characters will work. I stopped testing after 80,000 characters.<br /><strong>Opera (Browser)</strong><br />At least 190,000 characters will work. I stopped testing after 190,000 characters. Opera 9 for Windows continued to display a fully editable, copyable and pasteable URL in the location bar even at 190,000 characters.<br /><strong>Apache (Server)</strong><br />My early attempts to measure the maximum URL length in web browsers bumped into a server URL length limit of approximately 4,000 characters, after which Apache produces a &#8220;413 Entity Too Large&#8221; error. I used the current up to date Apache build found in Red Hat Enterprise Linux 4. The official Apache documentation only mentions an 8,192-byte limit on an individual field in a request.<br /><strong>Microsoft Internet Information Server</strong><br />The default limit is 16,384 characters (yes, Microsoft&#8217;s web server accepts longer URLs than Microsoft&#8217;s web browser). This is configurable.<br /><strong>Perl HTTP::Daemon (Server)</strong><br />Up to 8,000 bytes will work. Those constructing web application servers with Perl&#8217;s HTTP::Daemon module will encounter a 16,384 byte limit on the combined size of all HTTP request headers. This does not include POST-method form data, file uploads, etc., but it does include the URL. In practice this resulted in a 413 error when a URL was significantly longer than 8,000 characters. This limitation can be easily removed. Look for all occurrences of 16&#215;1024 in Daemon.pm and replace them with a larger value. Of course, this does increase your exposure to denial of service attacks.</p></blockquote></li><li>另外值得注意的是，有文章提到作为&lt;a&gt;的href属性时，URL不能超过1024bytes，这点没有详细查证 </li></ol></div>
<p>综上，URL还是不适合太长，不是不得已，尽量不要通过GET方式提交大量参数，可以考虑用POST方式（大约在2M左右，应该是和服务器及设定有关）。另外这么长的URL在访问和收藏（有文章提到有些浏览器在收藏超长地址时也是会出现问题）时也是相当不友好的。当然，之前数据库字段设置时还是作为255bytes处理，现在可能要考虑扩充一下了。</p>
<p>参考：</p>
<ol><li><a title="What is the maximum length of a URL?" href="http://www.boutell.com/newfaq/misc/urllength.html" target="_blank">What is the maximum length of a URL?</a> </li><li><a title="What is the limit on QueryString / GET / URL parameters?" href="http://classicasp.aspfaq.com/forms/what-is-the-limit-on-querystring/get/url-parameters.html" target="_blank">What is the limit on QueryString / GET / URL parameters?</a> </li></ol></div><img src ="http://www.blogjava.net/freeman1984/aggbug/399942.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2013-05-30 09:29 <a href="http://www.blogjava.net/freeman1984/archive/2013/05/30/399942.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle ORA-39212异常</title><link>http://www.blogjava.net/freeman1984/archive/2013/02/20/395438.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 20 Feb 2013 02:10:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2013/02/20/395438.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/395438.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2013/02/20/395438.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/395438.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/395438.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: ORA-39212&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2013/02/20/395438.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/395438.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2013-02-20 10:10 <a href="http://www.blogjava.net/freeman1984/archive/2013/02/20/395438.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于tomcat和sessionCookieName和SESSION_PARAMETER_NAME以及disableURLRewriting参数原理和使用</title><link>http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 24 Dec 2012 07:16:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/393402.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/393402.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/393402.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 关于tomcat和sessionCookieName和SESSION_PARAMETER_NAME以及disableURLRewriting参数原理和使用&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/393402.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-12-24 15:16 <a href="http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>bat 获取系统时间，并去掉时间小时前面的空格</title><link>http://www.blogjava.net/freeman1984/archive/2012/12/12/392840.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 12 Dec 2012 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/12/12/392840.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/392840.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/12/12/392840.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/392840.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/392840.html</trackback:ping><description><![CDATA[set h=%time:~0,2%<br />set h=%h: =0%<br />set bak_filename=%date:~0,4%%date:~5,2%%date:~8,2%%h%%time:~3,2%%time:~6,2%<br />返回如下：20121212093639<img src ="http://www.blogjava.net/freeman1984/aggbug/392840.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-12-12 09:38 <a href="http://www.blogjava.net/freeman1984/archive/2012/12/12/392840.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows xp 下office2010出现“windows installer 服务不能更新一个或多个受保护的”错误解决办</title><link>http://www.blogjava.net/freeman1984/archive/2012/11/07/390965.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 07 Nov 2012 07:36:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/11/07/390965.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/390965.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/11/07/390965.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/390965.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/390965.html</trackback:ping><description><![CDATA[<div>缺少相关文件所致，将以下文件 <a href="/Files/freeman1984/bin.rar">/Files/freeman1984/bin.rar</a>&nbsp;解压后放入C:\Program Files\Common Files\Microsoft Shared\web server extensions\40\bin下即可。<br />截图：<br /><img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/freeman1984/bin.png" /></div><img src ="http://www.blogjava.net/freeman1984/aggbug/390965.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-11-07 15:36 <a href="http://www.blogjava.net/freeman1984/archive/2012/11/07/390965.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A/B测试(转载)</title><link>http://www.blogjava.net/freeman1984/archive/2012/08/28/386419.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 28 Aug 2012 03:41:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/08/28/386419.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/386419.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/08/28/386419.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/386419.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/386419.html</trackback:ping><description><![CDATA[<p>A / B测试不是一个时髦名词。现在很多有经验的营销和设计工作者用它来获得访客行为信息，来提高转换率。然而， A / B测试与SEO不同的是，人们都不太知道徒河进行网站分析和可用性分析。他们并不完全明白它是什么或如何更有效的使用它。本文将为你提供有史以来最好的A / B测试教程。</p>
<p><strong>什么是A/B测试?</strong></p>
<p>A / B测试的核心就是：确定两个元素或版本（A和B）哪个版本更好，你需要同时实验两个版本。最后，选择最好的版本使用。</p>
<p><img class="alignnone size-full wp-image-2227" title="ab-testing" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/3063eb0c3e2e6ef65e81e1fee7c885a3.png" width="498" height="381" /></p>
<p>网络上的A / B测试，即你设计的页面有两个版本（A和B），A为现行的设计（称为控制） ， B是新的设计。比较这两个版本之间你所关心的数据（转化率，业绩，跳出率等） 。最后，您选择效果最好的版本。</p>
<p><strong>测试哪些东西?</strong></p>
<p>你要选择什么去测试取决于你的目标。例如，如果你的目标是增加顾客数量，那么您可能测试下列内容：注册表单数量，字段类型要求，隐私政策等。在这种情况下A / B测试的目标是要弄清楚什么阻止了游客注册。需要填写的表单的数量？用户的隐私？还是该网站做了让游客不信任的事情？所有这些问题都可以通过一个个A/B 测试获得答案。</p>
<p>每一个A / B测试内容都是独一无二的，单通常测试一下这些内容：</p>
<ul><li>行动按钮的措辞，大小，颜色和位置，</li><li>标题或产品说明，</li><li>表单的数量和字段类型，</li><li>网站的布局和风格，</li><li>产品定价和促销活动，</li><li>着陆和产品页面上的图片，</li><li>页面上文字的长度（少Vs多）。</li></ul>
<p>一旦你决定要测试什么，下一步当然是要选择一个合适的测试工具。如果你想要一个基础的免费工具，可以使用<a href="http://www.google.com/websiteoptimizer">Google Website Optimizer</a>。如果你想要功能更加强大的工具，可以使用<a href="http://visualwebsiteoptimizer.com/">Visual Website Optimizer</a>&nbsp; 。其他的一些选择都是可以的，建立试验在所有工具中都很相似，所以我们只需讨论一种即可。</p>
<p>你可以通过两种方法建立A / B测试：</p>
<ul><li><strong>在页面测试加载前替换元素</strong><br />如果你测试的是页面上的单个元素，如注册按钮，然后需要在测试工具中设置按钮。当测试时，在A / B工具将在页面给用户前随机替换按钮。</li><li><strong>重定向到另一页面</strong><br />如果你想通过A / B测试整个页面，比如说，一个绿色的主题和一个红色主题，那么你就需要创建和上传新的页面。例如，如果您的主页是 http://www.example.com/index.html，那么你需要创建另外一个页面 http://www.example.com/index1.html。当测试运行时，您的测试工具将一部分访问者重定向到第二个网址。</li></ul>
<p>一旦您使用了上面的两种变换方法，下一步是建立您的转换目标。通常，你会得到一个JavaScript代码，您可以复制并粘贴到一个需要游客到达的目标网页。例如，如果您有一个电子商务网站，你正在测试的&#8220;立即购买&#8220;按钮的颜色，然后您的转换目标将是购买成功后的&#8220;谢谢您&#8220;页面。</p>
<p>在转换事件发生的同时，在A / B测试工具，记录了哪种页面显示给了访问者。经过足够数量的游客，您可以确定哪个页面带来了最多的转化！建立和运行的A / B测试，其实很简单。</p>
<p><strong>该做什么和不该做什么</strong></p>
<p>虽然A / B测试是超级简单的概念，但是请记住，以下这些都只是我自己的经验。</p>
<p><strong>注意事项</strong></p>
<ul><li>不要分开你的测试情况。始终两个版本同时进行测试。如果您第一星期测试第一版本，第二星期测试第二个版本，你就错了。有可能B版本带来的流量更糟糕，但是带来了更好的业绩，因为两个版本之间的流量始终存在不一样。</li><li>不要结束得太早。有一个概念叫做&#8220;统计信心&#8220; ，无论你的测试结果明显的。如果你只有少数转换或游客，它都无法确定最终的结果。大多数A / B测试工具都有报告统计，但如果你是手动测试，你可以使用 <a href="http://visualwebsiteoptimizer.com/ab-split-significance-calculator/">在线计算器</a>。</li><li>不要让常客惊讶。如果你正在测试网站的一部分。包括新访客和常客，不要使他们觉得震惊。尤其不要因为哪些可能不会最终实施变化。</li><li>不要让你的直觉推翻了测试结果。在A / B测试的结果往往是令人惊讶的或直观的。在一个绿色为主题的网站，一个明显的红色按钮有可能成为赢家。即使红色按钮不容易吸引注意。您要测试的目标是一个更好的转换率，而不是美学，所以在得到测试借过钱不要拒绝任何尝试。</li></ul>
<p><strong>需要做的</strong></p>
<ul><li>知道运行测试多久。结束太早，可能会使你花了时间但是没有得到有意义的结果。结束太晚也不好，因为效果不佳的页面可能影响你的转化和业绩。使用一个<a href="http://visualwebsiteoptimizer.com/ab-split-test-duration/">计算器</a>，来确定测试多久以后来结束它。</li><li>将相同的页面呈献给同一个访客。您的工具应该有一个记忆访问者已经看到的页面的功能。这样可以防止向同一用户显示一不同的价格或不同的促销优惠。</li><li>让您的A / B测试在整个网站保持一致。如果你正在测试的登录按钮在多个地点出现，然后一个访问者应在所有的地方看到同样的变化。在页面1显示一个样子，在页面2显示两外一个样子，会使试验结果被干扰。</li><li>做很多的A / B测试。让我们面对现实吧：你的第一个A / B测试可能会无效。但是不要绝望。一个A / B测试只能有三个结果：没有结果，不好的结果和好的结果。优化转换率的关键是要做大量的A / B测试，把所有的好的结果拼接起来，最终推动业绩。</li></ul>
<p><strong>经典A/B测试案例研究</strong></p>
<p>这里有一些如何进行A/B测试的案例研究。</p>
<p><a href="http://37signals.com/svn/posts/1525-writing-decisions-headline-tests-on-the-highrise-signup-page">Writing Decisions: Headline Tests on the Highrise Sign-Up Page</a>&nbsp;37Signals测试他们的价格页面的标题。最终发现， &#8220;30-Day Free Trial on All Accounts &#8220;比原来的&#8220;Start a Highrise Account. &#8220;多产生30 ％以上的订单。</p>
<p><img class="alignnone size-full wp-image-2228" title="hrhq-signuphead-30day60sec" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/66e534c4fe2b5c4e1483f27ffcf4d9d3.png" width="530" height="140" /></p>
<p><a href="http://dustincurtis.com/you_should_follow_me_on_twitter.html">&#8220;You Should Follow Me on Twitter Here&#8221;</a> (Dustin Curtis) 这是一个用来测试召唤用户在Twitter上关注自己的试验。. Dustin 发现提示文字是&#8220;You should follow me on Twitter here&#8221; 的效果是&#8220;I&#8217;m on Twitter.&#8221; 173%</p>
<p><span><img class="alignnone size-full wp-image-2229" title="dustin" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/4a6eb53aa4fd0052d5fc82a45b0f8c7b.png" width="488" height="59" /></span></p>
<p><a href="http://carsonified.com/blog/design/human-photos-double-your-conversion-rate/">Human Photos Double Conversion Rates</a>&nbsp;从两个不同的A / B测试将在网站上增加转换率的人的照片：一个令人令人惊讶的结论，A/B测试两张图片，将真人照片放在网站上会获得一倍的转化。研究说明，我们潜意识被照片吸引了。</p>
<p><img class="alignnone size-full wp-image-2230" title="human" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/7fcea0efd7ae306f97f3aec87097bce8.png" width="415" height="184" /></p>
<p><a href="http://www.fourhourworkweek.com/blog/2009/08/12/google-website-optimizer-case-study/">Google Website Optimizer Case Study: Daily Burn, 20%+ Improvement</a> (Tim Ferriss) 一个将用户选择减少的变化使转化提高了20%，最终的版本在细节和文字上更易吸引目光。</p>
<p><img class="alignnone size-full wp-image-2231" title="gymnii" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/ec7bb024417da83432775f01d6791cc7.jpeg" width="300" height="241" /></p>
<p><a href="http://visualwebsiteoptimizer.com/split-testing-blog/ab-test-case-study-how-two-magical-words-increased-conversion-rate-by-28/">Two Magical Words Increased Conversion Rate by 28%</a>&nbsp;&#8220;It&#8217;s free&#8221; 这个单词增加了注册按钮点击次数的28%, 测试结果表明，在行动召唤上一些很小的变化会带来令人惊讶的结果。</p>
<p><img class="alignnone size-full wp-image-2232" title="its-free-shot" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/3b795b7011cb5afb70c96d2e3f0f9332.png" width="440" height="70" /></p>
<p><a href="http://dmix.ca/2010/05/how-we-increased-our-conversion-rate-by-72/">Changing the Sign-Up Button from Green to Red</a>&nbsp;依靠A / B测试， CareLogger把注册按钮从绿色修改为红色增加了34％转换率！</p>
<p><img class="alignnone size-full wp-image-2233" title="get-started" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/e5668dadf2bd002d01684a1e745ca8a3.png" width="580" height="122" /></p>
<p><a href="http://www.getelastic.com/single-vs-two-page-checkout/">Single page vs. multi-step checkout</a>&nbsp;如果你有一个在线商店，很常见的就是支付流程。这个A / B测试发现，多个支付流程比单个支付流程完成的销售更好。</p>
<p><img class="alignnone size-full wp-image-2234" title="getelastic" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/d3a976fd670d3c1ebe8015d629ad0f3a.jpeg" width="300" height="283" /></p>
<p><a href="http://www.lukew.com/ff/entry.asp?1007">&#8220;Mad Libs&#8221; style form increases conversion 25-40%</a>&nbsp;打败传统的智慧，此A / B测试发现一<em>段风格</em>形式输入字段比传统形式的布局更好。</p>
<p><img class="alignnone size-full wp-image-2235" title="madlibs" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/c7c204f8c987200255542d3678ab8d48.gif" width="558" height="164" /></p>
<p><a href="http://carsonified.com/blog/business/the-business-case-for-ab-testing/">Complete redesign of product page increased sales by 20%</a>&nbsp;一个软件产品的公司重新设计他们的产品页给它一个现代的外观和增加信任模块。最终结果：他们成功地增加20 ％的总销售额。本案例研究证明了设计对销售的影响。</p>
<p><img class="alignnone size-full wp-image-2236" title="aquasoft" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/cbf9c7829abaaef547ac2fe2dbe2e879.png" width="450" height="291" /></p>
<p><a href="http://www.marketingexperiments.com/blog/research-topics/response-capture-case-study.html">Marketing Experiments response capture case study &#8211; triple digit increase in conversions</a>&nbsp;通过优化邮件地址获取提高了258 ％。重点是消除所有的干扰，并要求游客只需提供电子邮件地址。使用亚马逊礼品卡让他/她的完成个人资料。</p>
<p><img class="alignnone size-full wp-image-2237" title="marketing-experiments" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/37b713d6f858ddd9bbd11d594b817b3b.jpeg" width="300" height="225" /></p>
<p><strong>A/B</strong><strong>测试工具</strong></p>
<p>有许多侧重点，价位和功能不同的A / B测试工具，这里是一些：</p>
<ul><li><a href="http://www.google.com/websiteoptimizer">Google Website Optimizer</a><br />搜索巨头提供的免费A/B测试工具。一个很好的入门级工具，但是没有一些先进的功能。</li><li><a href="http://www.bingocardcreator.com/abingo/">A/Bingo</a> and <a href="http://vanity.labnotes.org/">Vanity</a><br />基于Ruby on Rails开发的服务器组件。需要编程和代码集成。</li><li><a href="http://visualwebsiteoptimizer.com/">Visual Website Optimizer</a><br />一个易于使用的A / B测试工具，包含一些先进的功能，如所见即所得的编辑器，单击地图，访问者分割和标签等。</li><li><a href="http://unbounce.com/">Unbounce</a> and <a href="http://performable.com/">Performable</a><br />集成着陆页设计的A / B测试工具。</li><li><a href="http://vertster.com/">Vertster</a>, <a href="http://sitespect.com/">SiteSpect</a>, <a href="http://www.webtrends.com/products/optimize.aspx">Webtrends Optimize</a> and <a href="http://www.omniture.com/en/products/conversion/testandtarget">Omniture&#8217;s Test&amp;Target</a><br />企业级测试工具。</li></ul>
<p><strong>一些深入研究的A/B测试资料</strong></p>
<p>如果你已经读到这里，那么A / B测试大概已经激起你的兴趣。在这里，有一些非常好的A/B测试资源。</p>
<p><strong>寻找你下一个A/B测试的灵感</strong></p>
<ul><li><a href="http://whichtestwon.com/">Which Test Won?</a><br />一个猜测那种情况会最终胜利的游戏。</li><li><a href="http://www.conversion-rate-experts.com/articles/101-google-website-optimizer-tips/">101 A/B Testing Tips</a><br />大量的A/B测试技巧和方法。</li><li><a href="http://abtests.com/">ABtests.com</a><br />一个可以分享和阅读A/B测试结果的地方。</li><li><a href="http://visualwebsiteoptimizer.com/ideafox.php">A/B Ideafox</a><br />搜索引擎的A / B和多变量的案例研究。</li></ul>
<p><strong>一些介绍性文章</strong></p>
<ul><li><a href="http://elem.com/~btilly/effective-ab-testing/">Effective A/B Testing</a><br />By Ben Tilly.</li><li><a href="http://exp-platform.com/Documents/GuideControlledExperiments.pdf">Practical Guide to Controlled Experiments on the Web</a> (PDF)<br />From Microsoft Research.</li><li><a href="http://20bits.com/articles/an-introduction-to-ab-testing/">Introduction to A/B Testing</a><br />From the 20bits blog</li></ul>
<p><strong>A/B</strong><strong>测试中的数学</strong></p>
<ul><li><a href="http://20bits.com/articles/statistical-analysis-and-ab-testing/">Statistics for A/B Testing</a><br />From the 20bits blog.</li><li><a href="http://www.evanmiller.org/how-not-to-run-an-ab-test.html">How Not to Do A/B Testing</a></li><li><a href="http://visualwebsiteoptimizer.com/split-testing-blog/what-you-really-need-to-know-about-mathematics-of-ab-split-testing/">What You Should Know About the Mathematics of A/B Testing</a><br />From my own blog.</li><li><a href="http://blog.asmartbear.com/easy-statistics-for-adwords-ab-testing-and-hamsters.html">Easy Statistics for AdWords A/B Testing, and Hamsters</a></li><li><a href="http://www.cennydd.co.uk/2009/statistical-significance-other-ab-test-pitfalls/">Statistical Significance and Other A/B Test Pitfalls</a></li></ul>
<p>原文地址：<a href="http://www.smashingmagazine.com/2010/06/24/the-ultimate-guide-to-a-b-testing/">http://www.smashingmagazine.com/2010/06/24/the-ultimate-guide-to-a-b-testing/</a><br />转载自：<a href="http://ucdchina.com/snap/7203">http://ucdchina.com/snap/7203</a></p><img src ="http://www.blogjava.net/freeman1984/aggbug/386419.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-08-28 11:41 <a href="http://www.blogjava.net/freeman1984/archive/2012/08/28/386419.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>去空行备忘</title><link>http://www.blogjava.net/freeman1984/archive/2012/07/13/383021.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 13 Jul 2012 06:59:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/07/13/383021.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/383021.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/07/13/383021.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/383021.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/383021.html</trackback:ping><description><![CDATA[1 如何在ultraedit 去空行： 查找替换，选择正则表达式，替换内容输入：%[ ^t]++^p&nbsp; <br />2 如何在excel里面去空行：筛选-排序 即可。<img src ="http://www.blogjava.net/freeman1984/aggbug/383021.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-07-13 14:59 <a href="http://www.blogjava.net/freeman1984/archive/2012/07/13/383021.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate，spring管理事务中(transaction，JDBC connection，Hibernate Session的使用研究)（一）</title><link>http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 18 Nov 2011 03:25:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/363984.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/363984.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/363984.html</trackback:ping><description><![CDATA[如果单独使用hibernate可参考上一篇文章<a href="http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html">http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html</a><br /><br /><strong>首先hibernate的Connection release mode有以下几种：<br /></strong>1 after_statement 2 after_transaction 3 on_close 其中after_statement 用在jta中 ，<span style="color: red"><strong>on_close 是3.1之前遗留的（也许是为spring留的-_-），也就是3.1之前默认是on_close ，但3.1之后默认如果单独使用hibernate是after_transaction，</strong></span>如果有第三方事务管理，就用第三方提供的默认值，spring就是默认使用了on_close。<br /><strong>在spring管理事务中我们看看系统启动后默认使用的配置：<br /></strong>1,ransaction strategy: org.springframework.orm.hibernate3.SpringTransactionFactory使用spring事务策略<br />2，hibernate内部 Automatic session close at end of transaction: disabled 因为已经交给spring了<br />3&nbsp;&nbsp; Connection release mode: auto 默认，也就是没有配置hibernate.connection.release_mode的时候，但是这里有地方需要注意：也就是前面提到的使用第三方策略时的问题：看一下代码： 
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" /><span style="color: #000000">String&nbsp;releaseModeName&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;PropertiesHelper.getString(&nbsp;Environment.RELEASE_CONNECTIONS,&nbsp;properties,&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">auto</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;);<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">Connection&nbsp;release&nbsp;mode:&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;releaseModeName&nbsp;);<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConnectionReleaseMode&nbsp;releaseMode;<br /><img id="Codehighlighter1_246_311_Open_Image" onclick="this.style.display='none'; Codehighlighter1_246_311_Open_Text.style.display='none'; Codehighlighter1_246_311_Closed_Image.style.display='inline'; Codehighlighter1_246_311_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_246_311_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_246_311_Closed_Text.style.display='none'; Codehighlighter1_246_311_Open_Image.style.display='inline'; Codehighlighter1_246_311_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">auto</span><span style="color: #000000">"</span><span style="color: #000000">.equals(releaseModeName)&nbsp;)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_246_311_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_246_311_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: red">releaseMode&nbsp;</span><span style="color: red">=</span><span style="color: red">&nbsp;transactionFactory.getDefaultReleaseMode();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" /></span></span><span style="color: #000000"><br /><img id="Codehighlighter1_320_663_Open_Image" onclick="this.style.display='none'; Codehighlighter1_320_663_Open_Text.style.display='none'; Codehighlighter1_320_663_Closed_Image.style.display='inline'; Codehighlighter1_320_663_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_320_663_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_320_663_Closed_Text.style.display='none'; Codehighlighter1_320_663_Open_Image.style.display='inline'; Codehighlighter1_320_663_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000">&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_320_663_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_320_663_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;releaseMode&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.parse(&nbsp;releaseModeName&nbsp;);<br /><img id="Codehighlighter1_494_659_Open_Image" onclick="this.style.display='none'; Codehighlighter1_494_659_Open_Text.style.display='none'; Codehighlighter1_494_659_Closed_Image.style.display='inline'; Codehighlighter1_494_659_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_494_659_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_494_659_Closed_Text.style.display='none'; Codehighlighter1_494_659_Open_Image.style.display='inline'; Codehighlighter1_494_659_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;releaseMode&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.AFTER_STATEMENT&nbsp;</span><span style="color: #000000">&amp;&amp;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">!</span><span style="color: #000000">connections.supportsAggressiveRelease()&nbsp;)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_494_659_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_494_659_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.warn(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">Overriding&nbsp;release&nbsp;mode&nbsp;as&nbsp;connection&nbsp;provider&nbsp;does&nbsp;not&nbsp;support&nbsp;'after_statement'</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;);<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;releaseMode&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.AFTER_TRANSACTION;<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>其中红色部分就是调用了spring提供的默认值，而spring的默认值：在jta和cmt中都默认使用的是after_statement<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img id="Codehighlighter1_0_328_Open_Image" onclick="this.style.display='none'; Codehighlighter1_0_328_Open_Text.style.display='none'; Codehighlighter1_0_328_Closed_Image.style.display='inline'; Codehighlighter1_0_328_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_0_328_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_0_328_Closed_Text.style.display='none'; Codehighlighter1_0_328_Open_Image.style.display='inline'; Codehighlighter1_0_328_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_0_328_Closed_Text">/**&nbsp;*/</span><span id="Codehighlighter1_0_328_Open_Text"><span style="color: #008000">/**</span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Sets&nbsp;connection&nbsp;release&nbsp;mode&nbsp;"on_close"&nbsp;as&nbsp;default.<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&lt;p&gt;This&nbsp;was&nbsp;the&nbsp;case&nbsp;for&nbsp;Hibernate&nbsp;3.0;&nbsp;Hibernate&nbsp;3.1&nbsp;changed<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;it&nbsp;to&nbsp;"auto"&nbsp;(i.e.&nbsp;"after_statement"&nbsp;or&nbsp;"after_transaction").<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;However,&nbsp;for&nbsp;Spring's&nbsp;resource&nbsp;management&nbsp;(in&nbsp;particular&nbsp;for<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;HibernateTransactionManager),&nbsp;"on_close"&nbsp;is&nbsp;the&nbsp;better&nbsp;default.<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br /><img id="Codehighlighter1_384_428_Open_Image" onclick="this.style.display='none'; Codehighlighter1_384_428_Open_Text.style.display='none'; Codehighlighter1_384_428_Closed_Image.style.display='inline'; Codehighlighter1_384_428_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_384_428_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_384_428_Closed_Text.style.display='none'; Codehighlighter1_384_428_Open_Image.style.display='inline'; Codehighlighter1_384_428_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;ConnectionReleaseMode&nbsp;getDefaultReleaseMode()&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_384_428_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_384_428_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.ON_CLOSE;<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" /></span></div><br />而spring为什么要使用on_close ，而不是用after_transaction ,我们想想opensessioninview的原理也许能明白，session在view成还要使用，所以不能再transactio<span>n使用完后关闭JDBC connection，必须要在session之后，所以要使用on<strong>_close</strong></span><strong><span>（</span><span>也就是在on session(flush.auto，或者flush.Eagerly) 关闭）。这种情况hibernate内部还会在spring关闭JDBC connection后提示(费解，因为after transaction之后session没有关闭，但是&nbsp;Connection release mode配置的是on_close,session的关闭和&nbsp;Connection 的关闭都由spring来管理，hibernate就不知道了)，所以hibernate有好的提示如下(其实session，已经关闭。当然随着session的关闭jdbc链接释放回连接池)：</span><br /><span style="color: red">transaction completed on session with on_close connection release mode; be sure to cl</span></strong>ose the session to release JDBC resources!，<br /><br />。当然我们也可以使用after_transaction ，这种情况对使用编程式事务非常适用。<br />&nbsp;&nbsp;&nbsp;&nbsp;   <img src ="http://www.blogjava.net/freeman1984/aggbug/363984.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-11-18 11:25 <a href="http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jsessionid 问题分析</title><link>http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 02 Sep 2011 08:33:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/357833.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/357833.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/357833.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: JSESSIONID 问题分析&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/357833.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-09-02 16:33 <a href="http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IT项目管理的六种错误思维</title><link>http://www.blogjava.net/freeman1984/archive/2011/08/23/357095.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 23 Aug 2011 02:09:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/08/23/357095.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/357095.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/08/23/357095.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/357095.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/357095.html</trackback:ping><description><![CDATA[<p><strong>导读：在软件行业，在界面设计没有正式展现给客户之前，所有的工作都处于需求调研阶段。很多IT项目经理因为年轻，初生牛犊不怕虎，胆量大，勇气足，敢于在实践中引入新的工具、方法。敢于尝试不是坏事，但试验的风险一定要控制好。本文例举了在IT项目管理中常遇到的六种错误思维，给开发者们借鉴，学习，打造成功的IT项目管理。</strong></p>
<p><strong>内容如下：</strong></p>
<p><strong>错误一：错误的需求调研阶段，导致很多项目永远无法结束!</strong></p>
<p>在软件行业，在界面设计没有正式展现给客户之前，所有的工作都处于需求调研阶段。其实建筑行业已经给我们做好了先例：客户买房子之前是先要看看样板房和模型的，什么都看不到，这房子你敢买么?除非你不是自己住！而在我们所学的软件工程概念模型中，这是三个阶段：需求调研、需求分析、概要设计。</p>
<p>在客户把他们想要管理的业务模块以及与之相关的业务数据、流程、表单交付你的时候，你千万不要把这个阶段定性为需要调研结束，写出《需要规格说明书》就可以了。大量的实践证明，在概要设计阶段所衍生出来的需求工作量是之前的5~10倍，甚至更多，因为这要看设计人员的业务沟通能力和建模水平。</p>
<p>有实施经验比较丰富的项目管理人员总结说，在中国实施软件项目，必须以咨询方式展开：要推出自己的方案，而不能完全按照客户来提需求作项目。这是一种很好的解决思路，但无法解决所有实施项目的难题。这种解决方案的前提，要么项目实施者有成熟的业务模型，要么有成熟的产品(包含了成熟的业务模型)，否则是不可能做到的。但如果没有3~5年在同一行业，同一领域的实施经验和理论总结，没有哪家IT企业能达到这样的前提要求。</p>
<p>其实得出这样结论的深层原因，是因为国内多数企业管理思想不成熟，更谈不上完善的业务模型，所以客户的思维一定程度是发散的，还未形成系统。甚至还有些客户的领导，脑子中有很多新鲜的点子，他都有可能想在企业信息化的实施过程中加进来，这对把控项目范围和项目实施效果来说，都可能是灾难的开始。</p>
<p>所以，要做好实施项目，实施者必须有很好的业务建模能力，快速的给客户展示合理的软件原型软件Demo。</p>
<p>请记住：软件实施项目，一定要给用户看到样板房软件Demo，才算需求调研结束!</p>
<p><strong>错误二：IT技术人员不需要掌握项目管理</strong></p>
<p>有这种看法的人不在少数。根据观察，之所以形成这种看法，一是对项目的真正概念不清晰，二是对管理的概念神话了，把管理理解成了高深莫测，非一般人能做的事情。首先有必要普及一下项目的概念。</p>
<p>对项目有很多人下过定义，项目管理圣经PMBOK第三版(2004版)的定义是：为创造某个独特的产品或服务，或完成某独特的任务所做的临时性努力。围绕这句话PMBOK做了详细的解释和举例说明，很严谨，想了解的请学习PMBOK。因为都是翻译过来的定义，翻译得过于术语化很容易把人绕进去，在国内不排除已经拿到PMP认证证书的专业人士还搞不清楚项目究竟是什么。笔者在这里只想用汉语最通俗的语言来说明什么是项目和项目管理。</p>
<p>项目，就是在限定的时间要人完成的事。记住三个关键字即可把握：人、时、事。</p>
<p>项目管理就是参与者用什么(知识、技能、工具、方法)来圆满地干好这件事。</p>
<p>明白了这些，你就会明白从日常生活的吃喝拉撒到国家管理，处处都是项目，处处都需要项目管理，也就能明白每个人都需要项目管理，也就能理解学会了项目管理将会多么受益无穷，娴熟运用项目管理思维将无往不胜!</p>
<p>但需要提醒大家一点，现在的PMBOK是把传统制造行业、建筑行业、IT行业等多个行业领域的项目管理知识糅合到了一起，大而全，但针对性不够好，所以很多人觉得PMBOK理论化太强，学完了觉得很多东西没用。现在国际知名的另外一套项目管理认证，IPMP是按照工作岗位能力进行了分级，也没有针对行业进行分解。所以，无论拿到PMP或者IPMP，很多人都会有同样的困惑。据了解，PMI已经准备做这样的改进，这是一个很好的消息。</p>
<p><strong>错误三：忘记项目目标</strong></p>
<p>你看到这个题目什么感觉?很多人会觉得这样的错误怎么会发生?几乎没有人会认为自己犯这个错误！忘记项目目标有两种情形：一是从开始接手项目就没弄清楚项目的目标是什么;二是虽然清楚项目的目标是什么，但却干着跟完成项目目标无关、甚至有害的事。</p>
<p>时刻铭记项目目标是项目管理很重要的一个思维，项目所有的活动都围绕这个展开。可是随着项目的逐步开展，尤其是复杂项目：人多、事多、周期长，很多项目经理会逐渐因为个人喜好而忘记了项目的大目标，比较典型的有：技术出身的项目经理会沉迷于技术细节，大量时间花在学习新技术或者一头闷在解决技术难题上;脾气火爆的项目经理会因为很多不值当的事情大发脾气，把团队搞得乌烟瘴气;小心眼、爱面子的项目经理会因为某个组员无意的顶撞而怀恨在心，从此总给其穿小鞋，搞得团队拉帮结派，毫不团结;还有更糟糕的，比如爱玩游戏的，爱喝小酒的等等。所有这些，无论原因是自身不成熟，还是管理经验、管理能力不足，结果都一样，那就是项目出问题，甚至失败。</p>
<p>项目经理最重要的一项任务就是跟踪与控制，时刻把握项目方向，保证项目计划得以顺利执行，偏差控制在可控风险范围内。但项目总是有太多意外因素，尤其是周期长的项目，人们常用夜长梦多来形容风险会随时间的延长而增加，所以项目经理一定时刻都要保持头脑清醒，对项目无益的事情不做，对项目有风险的事情更不能做。</p>
<p>任何项目在开展过程中都会不断面对机会和诱惑，项目经理一定要能明确项目大目标，才能清晰地识别哪些是使项目成功的机会，哪些是会给项目带来风险的诱惑，才会少走弯路，早日成功。项目管理者联盟，项目管理问题。</p>
<p>人是需要不断被提醒的，这由人性决定。智慧的人能够不断的反省从而自我提醒，愚笨的人会被挫折、外界的警示不断提醒，这就形成了成功与失败的差异。</p>
<p><strong>错误四：计划不能变</strong></p>
<p>怎样才能保证项目成功?计划，计划，再计划，这是项目管理的最佳实践！所以，做项目管理的一般都知道如何编制项目计划，并且很多人能熟练的使用Project工具，知道80小时或者40小时法则、WBS和关键路径的概念。每个项目经理都会记住计划一旦形成，就严格按照计划去执行，而不受某个人、某件事的影响这个原则，也明白这样做不仅能够减少大量资源的浪费，产品的质量也能得到保障。所以，很多项目经理排斥，甚至拒绝改变计划。坚持原则，这貌似没什么错，但真的这样么?</p>
<p>要弄清楚一件事是否有必要做，首先就得弄清楚两个问题：一、这件事为什么要做?二、做了有什么好处?</p>
<p>那我们首先问一下编制计划的目的是什么?我们知道计划是项目管理的最佳实践，计划是保证项目成功的一种手段和方法，做这件事只有一个目的，那就是为了保证项目成功，但前提是，这份计划是周密的、可行的。严格执行一份周密可行的项目计划才能保证项目成功。很多项目经理记住了上面的严格执行原则，但忘记了这个大前提。</p>
<p>第二个问题，计划有什么好处?项目管理的计划方法，把项目活动、持续时间、所需资源有机地结合在一起，并且有严格的先后次序、里程碑和关键路径，可以清晰地提醒项目所有成员在什么时间，做什么事情，保证每个项目任务都得以执行;通过对计划的执行跟踪，项目经理可以清晰地了解项目进展情况和偏差情况，评估并及时有效的控制项目风险，从而保证项目的成功。</p>
<p>明白了这两点，我们再来看IT项目。对多数IT项目，尤其是软件实施项目，启动时都存在范围不够明晰，需求不确定的情况。只有到软件Demo产生，才可能需求清晰，范围确定，这些情况就决定了IT项目计划需要根据项目的实际情况及时进行修正。如何压缩范围确定的时间，早日制定出周密可行的计划，是软件项目的一个重要课题。</p>
<p>制定一份周密可行的计划是项目经理优秀能力的体现，尤其是WBS的制定，对复杂项目有很大难度。在谈2008奥运项目的管理体会时，项目专家曹蕾就提到奥运会项目最难的一点就是WBS的制定(参见PMU网站对2008奥运项目的访谈)。要保证项目的成功，就要保证项目的每个活动都能得以顺利执行。所以，在项目情况发生变化，在原有的计划基础上有需求变更时，就要把新的任务补充到计划中，修正计划，确保WBS的完整，确保计划周密可行，之后的工作才是严格执行。</p>
<p>顺便提一句，有些项目经理会走另外一个极端：因为需求不确定，所以不制定项目计划。这同样是对计划的错误理解。即使计划不够周密，但它可以提醒我们项目的大目标是什么，保证项目团队所采取的行动不偏离大方向。任何一项大的项目，都可以拆分成很多小项目，WBS的渐进明细，也是项目必须完成的任务之一，所有任务的持续时间都是要估算的，即使不够准确，至少可以作为经验累积，为今后的准确估算做了准备。因此，项目的任何阶段都一定要有计划。</p>
<p><strong>错误五：项目一定要盈利</strong></p>
<p>项目一定要盈利，这句话被无数IT项目经理奉为真理，也就注定了要创造很多悲剧！为了达到这个目的，很多IT项目经理甚至都在悉心研究厚黑学，学习用什么办法把小弟搞得热情高涨，比民工累，从而用最低的成本创造最大的利润。</p>
<p>项目管理作为战术层次的管理手段，一定要服务于战略层次的大方向。商场如战场，有胜利就会有失败。为了战略胜利，很多战役要诱敌深入，必须打败仗。败仗不要紧，关键要弄清楚败到什么层次，损失到何种地步，明确本次战役的真实目标，再去打这场战役，就会做到驾轻就熟，从而不至于到最后形成不仅损兵折将，还未能诱敌深入的局面。</p>
<p>开拓市场、占领市场、站稳市场、挖掘市场，这是每个公司发展必不可少的步骤。很多项目，对公司来说都是为了占领市场，甚至虎口夺食。这样的项目，公司从战略层面首先要求的绝对不是盈利，而是如何能把市场占领，继而站稳，项目经理必须明白这个战略意图。</p>
<p>平衡是项目管理最为重要的一个思想，从过去的做好质量、时间、成本项目三要素的平衡，到现在满足相关干系人的需求，所有的最佳实践和理论研究成果，都绝不会提倡走极端，杀机取卵！利润只是项目的一个目标，并且一定要明白有短期利润和长期利润之分，过分单一追求利润的项目注定要失败，过分追求利润的公司也不会长久。</p>
<p>该花的钱不能省，不该花的钱一分也不要花，项目经理把成本控制在合理的预算范围内，就是成本控制的成功。万万不可为了把一个注定要赔钱的项目做得盈利而想尽办法、绞尽脑汁压缩成本，从而让组员加班加点，玩命干活，到最后，项目干完了，人也走/光了，还极有可能因为赶工导致项目质量不合格，客户不满意，那就真的赔了夫人又折兵!</p>
<p>项目组要能保持激情高效，不能懒散拖沓，项目经理一定要把握好这个度，绝不能走极端。平衡是一门艺术，也是展示项目经理能力水平的一个重要标尺！</p>
<p><strong>错误六：记住了科学，忘记了有效</strong></p>
<p>学以致用，就怕乱用。无论是产品、技术还是管理方法，都存在为了更先进、更科学而罔顾现实，盲目乱用的现象，结果先进和科学的技术、工具不仅未提高生产效率，却成了累赘，这样的情况到处都是，在IT项目中也为数不少。</p>
<p>国内大量失败的ERP项目就是这类错误的典型。有人把ERP项目归结为一把手工程，意思是只有领导重视并推动才能成功。领导支持是项目成功很重要的一个条件，但绝不是有领导支持就一定能够成功。有些项目就是领导决策失误盲目上的，从开始就注定项目要失败。一个信息化项目的实施，对很多企业来说就是一场大的改革，对所有员工从思维、技能到工作习惯等多方面都需要进行调整。如果企业的员工素质不能跟上，纵然有各种各样的培训，但不顾员工基础和学习曲线，用户不能真正掌握全新的系统，结果就只能增加用户负担，而产生不了期望的效果。</p>
<p>很多IT项目经理在学习了一些新的技术后，总想立刻在项目中实践，而不去仔细分析这些技术在这个项目中是否需要，是否适合。IT技术日新月异，不断有新的理论被提出来，被翻译引进到国内。有些项目经理在一知半解，对这些技术还不是很熟悉的情况下，就敢向人吹嘘他所掌握技术的科学性、先进性，进而强制要求在项目中实践。这可能是甲方的项目经理，也可能是乙方的项目经理。因为技术选择错误导致项目失败的例子在国内过去有，现在也还有!绝对不可准备不足，大范围引入全新的技术，待到项目时间过去一半了，才发现选择的技术不适用，那时候一切都晚了。掌握任何新东西都有学习曲线，项目的时间限制是项目经理必须时刻牢记的要素，把握不好就会给项目带来极大风险。</p>
<p>涉及到具体的IT项目管理，PMBOK的知识体系可谓博大，还有一些其他新的项目管理工具，不能说不先进，但是哪些知识、工具、方法适合本项目，需要项目经理根据实情，认真分析后进行筛选使用。</p>
<p>科学、先进、好用等等修饰头衔这些都不是要选择的首要理由，需要、适用和有效才是首要考虑的事情。很多IT项目经理因为年轻，初生牛犊不怕虎，胆量大，勇气足，敢于在实践中引入新的工具、方法。敢于尝试不是坏事，但试验的风险一定要控制好。对于项目经理来说，所有的决策都要围绕项目目标进行。项目经理的首要任务是保证项目成功，如果同时能引入新的技术、工具，增加组员的知识技能，提升项目组工作效率，提高产品的质量和可靠性，绝对是锦上添花，但绝对不能为了锦上添花而导致项目失控甚至失败，捡了芝麻，丢了西瓜!<br />转自：<a href="http://sd.csdn.net/a/20110819/303332.html">http://sd.csdn.net/a/20110819/303332.html</a></p><img src ="http://www.blogjava.net/freeman1984/aggbug/357095.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-08-23 10:09 <a href="http://www.blogjava.net/freeman1984/archive/2011/08/23/357095.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用hibernate中connection.release_mode，connection.autocommit和transaction.auto_close_session用法及需要注意的问题</title><link>http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 04 Aug 2011 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/355808.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/355808.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/355808.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: connection.release_mode，connection.autocommit和transaction.auto_close_session用法 <br>&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/355808.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-08-04 15:57 <a href="http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大家都用什么bug管理软件？</title><link>http://www.blogjava.net/freeman1984/archive/2011/06/20/352649.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 20 Jun 2011 03:38:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/06/20/352649.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/352649.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/06/20/352649.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/352649.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/352649.html</trackback:ping><description><![CDATA[&nbsp; 公司以前用的mantis，冒失功能太简单了，二次开发比较困难。现在想和公司的项目管理软件平台（java语言）集成，不知道大家有什么经验分享一下？？，或者介绍几个二次开发容易一点的！<img src ="http://www.blogjava.net/freeman1984/aggbug/352649.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-06-20 11:38 <a href="http://www.blogjava.net/freeman1984/archive/2011/06/20/352649.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>websphere： EAR 文件可能是损坏的或不完整的问题</title><link>http://www.blogjava.net/freeman1984/archive/2011/06/01/351492.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 01 Jun 2011 02:35:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/06/01/351492.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/351492.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/06/01/351492.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/351492.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/351492.html</trackback:ping><description><![CDATA[<br />&nbsp; 今天在websphere上部署项目的时候出现&nbsp;EAR 文件可能是损坏的或不完整的问题，最后查了半天才发现时web.xml里面的filter和filter-maping写的顺序不对。解决后ok。<br /><br />&nbsp;建议： 如果用myeclipse开发可以使用右键 myeclipse-&gt;run validate 验证下web.xml这样就会发现问题了。<br /><br />&nbsp; 这也算是websphere和tomcat的一个区别吧。 <img src ="http://www.blogjava.net/freeman1984/aggbug/351492.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-06-01 10:35 <a href="http://www.blogjava.net/freeman1984/archive/2011/06/01/351492.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unable to open kernel device "\\.\vmci"_</title><link>http://www.blogjava.net/freeman1984/archive/2011/04/30/349328.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sat, 30 Apr 2011 14:23:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/04/30/349328.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/349328.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/04/30/349328.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/349328.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/349328.html</trackback:ping><description><![CDATA[<p>Unable to open kernel device "": 系统找不到指定的文件. Did you reboot after installing VMware Workstation?<br />
Module DevicePowerOn power on failed.</p>
<p>&nbsp;</p>
<p>有一段时间不用虚拟机了，今天又要用到虚拟机。开机虚拟机后，Power on出现上述信息</p>
<br />
解决办法：开始-》运行：
<p><span style="color: #ff0000">net start vmci<br />
原因：</p>
<p><span style="color: #ff0000">Sometimes WS 6.5.0 does not start this automatically</span></p>
</span>
<img src ="http://www.blogjava.net/freeman1984/aggbug/349328.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-04-30 22:23 <a href="http://www.blogjava.net/freeman1984/archive/2011/04/30/349328.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务 的解决方法</title><link>http://www.blogjava.net/freeman1984/archive/2011/04/15/348350.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 15 Apr 2011 06:58:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/04/15/348350.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/348350.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/04/15/348350.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/348350.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/348350.html</trackback:ping><description><![CDATA[<div class="articalTitle">
<p>早上同事用PL/SQL连接虚拟机中的Oracle数据库，发现又报了&#8220;<strong><font color="#ff0000">ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务</font></strong>&#8221;错误，帮其解决后，发现很多人遇到过这样的问题，因此写着这里。</p>
<p>也许你没有遇到过，原因如下：</p>
<p>你oracle安装成功后，一直未停止数据库（即数据库是启动的），客户端配置成功后，应该一直不会有什么问题。</p>
<p>而一旦你和我同事一样，有时把Oracle安装在虚拟机中，而且Oracle安装完毕后，没在进行任何监听的配置，则虚拟机再启动，则就会出现ORA-12514的问题。如下图</p>
<p align="center"><img title="ORA-12514&nbsp;<wbr  alt="  ? />TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" name=image_operate_32961295504739984 alt="ORA-12514&nbsp;<wbr>TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" src="http://s7.sinaimg.cn/middle/5007d1b1g9a40c1c8ebf6&amp;690" width=378 height=106&gt;</p>
<p>如下是解决思路：</p>
<p>根据出错信息判断出客户端未监听到实例服务名</p>
<p>1、通过重启服务的方式启动数据库，再次连接仍无法连接服务器。</p>
<p>2、既然第一种方法不能解决问题，那就第二种方法。考虑监听<font color="#ff0000"><strong>listener.ora</strong></font></p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>监听配置文件listener.ora中可以不必指定监听的服务名（安装Oracle10g后也是没有指定的）。正常情况下一般只要数据库启动，客户端连接数据库也没有什么问题，但是有时重复启动关闭也会出现ORA-12514错误。</p>
<p>&nbsp;<wbr>&nbsp;<wbr> 既然listener.ora中没有指定监听，我们可以在listener.ora文件中指定监听的实例名，这样该问题应该可以连接。</p>
<p>步骤如下：</p>
<ul><li>在oracle服务器Oracle安装目录（我的在E:\Oracle10g下，每个人的不一样，根据自己的情况查找）Network/admin目录下找到listener.ora 我的如下图所示 </li></ul>
<p># listener.ora Network Configuration File: E:\Oracle10g\network\admin\listener.ora<br /># Generated by Oracle configuration tools.</p>
<p>SID_LIST_LISTENER =<br />&nbsp;<wbr> (SID_LIST =<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (SID_DESC =<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (SID_NAME = PLSExtProc)<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (ORACLE_HOME = E:\Oracle10g)<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (PROGRAM = extproc)<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> )<br /><strong><font color="#ff0000">&nbsp;<wbr>&nbsp;<wbr> (SID_DESC =<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (GLOBAL_DBNAME = ORCL)<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (ORACLE_HOME = E:\Oracle10g)<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (SID_NAME = ORCL)<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> )</font></strong><br />&nbsp;<wbr>)</p>
<p>LISTENER =<br />&nbsp;<wbr> (DESCRIPTION_LIST =<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (DESCRIPTION =<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> (ADDRESS = (PROTOCOL = TCP)(HOST = onest)(PORT = 1521))<br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> )<br />&nbsp;<wbr> )</p>
<p>标红的为我添加的部分，ORCL为监听的实例名。</p>
<ul><li>然后在Oracle服务器的服务中重新启动监听服务<img title="ORA-12514&nbsp;<wbr  alt="  ? />TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" name=image_operate_641295504618796 alt="ORA-12514&nbsp;<wbr>TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" src="http://s16.sinaimg.cn/middle/5007d1b1g9a4102276c5f&amp;690" real_src="http://s16.sinaimg.cn/middle/5007d1b1g9a4102276c5f&amp;690"&gt;，然后在oracle客户端通过再次配置对Orcl实例的监听，如下图所示<img title="ORA-12514&nbsp;<wbr  alt="  ? />TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" name=image_operate_40861295504642796 alt="ORA-12514&nbsp;<wbr>TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" src="http://s6.sinaimg.cn/middle/5007d1b1g9a410a2805c5&amp;690" width=476 height=86 real_src="http://s6.sinaimg.cn/middle/5007d1b1g9a410a2805c5&amp;690"&gt;</li><li>结果出现如下图的提示。<br /><img title="ORA-12514&nbsp;<wbr  alt="  ? />TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" name=image_operate_14831295504695718 alt="ORA-12514&nbsp;<wbr>TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" src="http://s13.sinaimg.cn/middle/5007d1b1g9a40c26294dc&amp;690" width=598 height=401 real_src="http://s13.sinaimg.cn/middle/5007d1b1g9a40c26294dc&amp;690"&gt;</li><li>这时我们不要着急，只需要oracle服务器重新启动一下，再次连接即成功。这也是我们配置完listener.ora 监听后，经常忘记的。再次尝试，可以看到客户端可以连接上oracle服务器了，而且PL/SQL再次连接也没有问题了。 </li></ul>
<p>而有些朋友在配置客户端时，连接数据库成功，而使用PL/SQL时，又出现了如下图所示的问题。这又如何解决呢？为什么oracle客户端已经连接成功了，而PL/SQL确不行呢？<br /><br /></p>
<p align="center"><img title="ORA-12514&nbsp;<wbr  alt="  ? />TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" name=image_operate_78131295504727281 alt="ORA-12514&nbsp;<wbr>TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" src="http://s3.sinaimg.cn/middle/5007d1b1g9a40c320fad2&amp;690" width=436 height=288 real_src="http://s3.sinaimg.cn/middle/5007d1b1g9a40c320fad2&amp;690"&gt;</p>
<p><br />出现如上的原因是，可能是大家再配置oracle客户端时，虽然链接成功了，步骤上可能有些错误。大家使用Net Cofiguration Assistant客户端时重新配置了Orcl，而不是添加，我们应该如下步骤处理，就不会出问题了。</p>
<p>1、如果Net Cofiguration Assistant中已经有了Orcl。我们可以重新配置</p>
<p>2、如果Net Cofiguration Assistant中没有Orcl，我们应该添加&nbsp;<wbr> 具体界面如下图所示。</p>
<p align="center"><img title="ORA-12514&nbsp;<wbr  alt="  ? />TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" name=image_operate_52121295504778234 alt="ORA-12514&nbsp;<wbr>TNS&nbsp;<wbr>监听程序当前无法识别连接描述符中请求服务&nbsp;<wbr>的解决方法" src="http://s5.sinaimg.cn/middle/5007d1b1g9a412cc6e6d4&amp;690" width=594 height=397 real_src="http://s5.sinaimg.cn/middle/5007d1b1g9a412cc6e6d4&amp;690"&gt;</p>
<p align="left">如果大家该步处理也没有问题了，listener.ora 修改成功，并且重新启动了oracle服务器，无论oracle客户端还是PL/SQL都能够成功连接数据库了。</p>
<p align="left">总结一下。当大家遇到&#8220;<strong><font color="#ff0000">ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务</font></strong>&#8221;错误的解决步骤：</p>
<p align="left">1、通过重启服务的方式启动数据库，再次连接尝试。</p>
<p align="left">2、如果第一种方法不可行，我们采用第二种方法</p>
<ul><li>
<div align="left">正确添加listener.ora；</div></li><li>
<div align="left">重新启动了oracle服务器，并检查oracle所有服务是否启动；</div></li><li>
<div align="left">oracle客户端Net Cofiguration Assistant正确添加或重新配置实例名&nbsp;<wbr></div></li></ul>转载自：http://blog.sina.com.cn/s/blog_5007d1b10100oqo8.html</div><img src ="http://www.blogjava.net/freeman1984/aggbug/348350.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-04-15 14:58 <a href="http://www.blogjava.net/freeman1984/archive/2011/04/15/348350.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>提高AJAX客户端响应速度(转载)</title><link>http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 11 Feb 2011 07:23:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/344056.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/344056.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/344056.html</trackback:ping><description><![CDATA[&nbsp;
<h1 style="text-align: left" align="left"><span style="font-family: 宋体">提高</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">客户端响应速度</span></h1>
<p>(<span style="font-family: 宋体">文：包一磊</span>)</p>
<p style="text-align: left; margin: 15.6pt 0cm" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">的出现极大的改变了</span><span style="font-family: 'Verdana', 'sans-serif'">Web</span><span style="font-family: 宋体">应用客户端的操作模式，它使的用户可以在全心工作时不必频繁的忍受那令人厌恶的页面刷新。理论上</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">技术在很大的程度上可以减少用户操作的等待时间，同时节约网络上的数据流量。而然，实际情况却并不总是这样。用户时常会抱怨用了</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">的系统响应速度反而降低了。</span></p>
<p style="text-align: left; margin: 15.6pt 0cm" class="MsoNormal" align="left"><span style="font-family: 宋体">笔者从事</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">方面的研发多年，参与开发了目前国内较为成熟的</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">平台</span><span style="font-family: 'Verdana', 'sans-serif'">-dorado</span><span style="font-family: 宋体">。根据笔者的经验，导致这种结果的根本原因并不在</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">。很多时候系统响应速度的降低都是由不够合理的界面设计和不够高效的编程习惯造成的。下面我们就来分析几个</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">开发过程中需要时刻注意的环节。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">合理的使用客户端编程和远程过程调用。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">客户端的编程主要都是基于</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">的。而</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">是一种解释型的编程语言，它的运行效率相对于</span><span style="font-family: 'Verdana', 'sans-serif'">Java</span><span style="font-family: 宋体">等都要稍逊一筹。同时</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">又是运行在浏览器这样一个严格受限的环境当中。因此开发人员对于哪些逻辑可以在客户端执行应该有一个清醒的认识。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">在实际的应用中究竟应该怎样使用</span><span style="font-family: 宋体">客户端编程，这依赖于开发人员的经验判断。这里很多问题是只可意会的。由于篇幅有限，在这里我们大致归纳出下面这几个注意事项：</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 63pt; tab-stops: list 63.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">u&nbsp;</span><span style="font-family: 宋体">尽可能避免频繁的使用远程过程调用，例如避免在循环体中使用远程过程调用。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 63pt; tab-stops: list 63.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">u&nbsp;</span><span style="font-family: 宋体">如果可能的话尽可能使用</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">方式的远程过程调用（异步方式的远程过程调用）。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 63pt; tab-stops: list 63.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">u&nbsp;</span><span style="font-family: 宋体">避免将重量级的数据操作放置在</span><span style="font-family: 宋体">客户端。例如：大批量的数据复制操作、需要通过大量的数据遍历完成的计算等。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">改进对</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的操作方式。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">客户端的编程中，对</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的操作往往是最容易占用</span><span style="font-family: 'Verdana', 'sans-serif'">CPU</span><span style="font-family: 宋体">时间的。而对于</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的操作，不同的编程方法之间的性能差异又往往是非常大的。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">以下是三段运行结果完全相同的代码，它们的作用是在网页中创建一个</span><span style="font-family: 'Verdana', 'sans-serif'">10x1000</span><span style="font-family: 宋体">的表格。然而它们的运行速度却有着天壤之别。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">1 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 41</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">*/</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var table = document.createElement("TABLE");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">document.body.appendChild(table);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for(var i = 0; i &lt; 1000; i++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;var row = table.insertRow(-1);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;for(var j = 0; j &lt; 10; j++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp; var cell = objRow.insertCell(-1);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; cell.innerText = "( " + i + " , " + j + " )";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">2 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 7.6</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var table = document.getElementById("TABLE");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">document.body.appendChild(table);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var tbody = document.createElement("TBODY");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">table.appendChild(tbody);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for(var i = 0; i &lt; 1000; i++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;var row = document.createElement("TR");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;tbody.appendChild(row);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;for(var j = 0; j &lt; 10; j++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp; var cell = document.createElement("TD");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; row.appendChild(cell);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; cell.innerText = "( " + i + " , " + j + " )";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">3 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 1.26</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var tbody = document.createElement("TBODY");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for(var i = 0; i &lt; 1000; i++){&nbsp;&nbsp; </span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;var row = document.createElement("TR");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(var j = 0; j &lt; 10; j++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp; var cell = document.createElement("TD");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; cell.innerText = "( " + i + " , " + j + " )";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; row.appendChild(cell);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;tbody.appendChild(row);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var table = document.getElementById("TABLE");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">table.appendChild(tbody); </span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">document.body.appendChild(table);</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">这里的&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">1</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;之间的差别在于在创建表格单元时使用了不同的</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">方法。而&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">3</span><span style="font-family: 宋体">&#8221;</span><span style="font-family: 宋体">之间的差别在于处理顺序的略微不同。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">1</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;之间如此大的性能差别我们无从分析，目前所知的是</span><span style="font-family: 'Verdana', 'sans-serif'">insertRow</span><span style="font-family: 宋体">和</span><span style="font-family: 'Verdana', 'sans-serif'">insertCell</span><span style="font-family: 宋体">是</span><span style="font-family: 'Verdana', 'sans-serif'">DHTML</span><span style="font-family: 宋体">中表格特有的</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">，</span><span style="font-family: 'Verdana', 'sans-serif'">createElement</span><span style="font-family: 宋体">和</span><span style="font-family: 'Verdana', 'sans-serif'">appendChild</span><span style="font-family: 宋体">是</span><span style="font-family: 'Verdana', 'sans-serif'">W3C DOM</span><span style="font-family: 宋体">的原生</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">。而前者应该是对后者的封装。不过，我们并不能因此而得出结论认为</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">的原生</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">总是优于对象特有的</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">。建议大家在需要频繁调用某一</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">时，对其性能表现做一些基本的测试。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">3</span><span style="font-family: 宋体">&#8221;之间的性能差异主要来自于他们的构建顺序不同。&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;的做法是首先创建最外层的</span><span style="font-family: 'Verdana', 'sans-serif'">&lt;TABLE&gt;</span><span style="font-family: 宋体">对象，然后再在循环中依次创建</span><span style="font-family: 'Verdana', 'sans-serif'">&lt;TR&gt;</span><span style="font-family: 宋体">和</span><span style="font-family: 'Verdana', 'sans-serif'">&lt;TD&gt;</span><span style="font-family: 宋体">。而&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">3</span><span style="font-family: 宋体">&#8221;的做法是首先在内存中由内到外的构建好整个表格，最后再将它添加到网页中。这样做的目的是尽可能的减少浏览器重新计算页面布局的次数。每当我们将一个对象添加到网页中时，浏览器都会尝试对页面中的控件的布局进行重新计算。所以，<span style="color: blue">如果我们能够首先在内存中将整个要构造的对象全部创建好，然后再一次性的添加到网页中。那么，浏览器将只会做一次布局的重计算</span>。总结为一句话那就是越晚执行</span><span style="font-family: 'Verdana', 'sans-serif'">appendChild</span><span style="font-family: 宋体">越好。有时为了提高运行效率，我们甚至可以考虑先使用</span><span style="font-family: 'Verdana', 'sans-serif'">removeChild</span><span style="font-family: 宋体">将已存在的控件从页面中移除，然后构造完成后再重新将其放置回页面当中。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">提高字符串累加的速度</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">在使用</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">提交信息时，我可能常常需要拼装一些比较大的字符串通过</span><span style="font-family: 'Verdana', 'sans-serif'">XmlHttp</span><span style="font-family: 宋体">来完成</span><span style="font-family: 'Verdana', 'sans-serif'">POST</span><span style="font-family: 宋体">提交。尽管提交这样大的信息的做法看起来并不优雅，但有时我们可能不得不面对这样的需求。那么</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">中对字符串的累加速度如何呢？我们先来做下面的这个实验。累加一个长度为</span><span style="font-family: 'Verdana', 'sans-serif'">30000</span><span style="font-family: 宋体">的字符串。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">1 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 14.325</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i = 0; i &lt; 50000; i++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str += "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">这段代码耗时</span><span style="font-family: 'Verdana', 'sans-serif'">14.325</span><span style="font-family: 宋体">秒，结果并不理想。现在我们将代码改为如下的形式：</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">2 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 0.359</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i = 0; i &lt; 100; i++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var sub = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var j = 0; j &lt; 500; j++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sub += "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str += sub;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">这段代码耗时</span><span style="font-family: 'Verdana', 'sans-serif'">0.359</span><span style="font-family: 宋体">秒！同样的结果，我们做的只是首先拼装一些较小的字符串然后再组装成更大的字符串。这种做法可以有效的在字符串拼装的后期减小内存复制的数据量。知道了这一原理之后我们还可以把上面的代码进一步拆散以后进行测试。下面的代码仅耗时</span><span style="font-family: 'Verdana', 'sans-serif'">0.140</span><span style="font-family: 宋体">秒。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">3 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 0.140</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str = "";&nbsp;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i1 = 0; i1 &lt; 5; i1++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str1 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i2 = 0; i2 &lt; 10; i2++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str2 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i3 = 0; i3 &lt; 10; i3++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str3 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i4 = 0; i4 &lt; 10; i4++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str4 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i5 = 0; i5 &lt; 10; i5++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str4 += "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str3 += str4;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str2 += str3;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str1 += str2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str += str1;&nbsp;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">不过，上面这种做法也许并不是最好的！如果我们需要提交的信息是</span><span style="font-family: 'Verdana', 'sans-serif'">XML</span><span style="font-family: 宋体">格式的（其实绝大多数情况下，我们都可以设法将要提交的信息组装成</span><span style="font-family: 'Verdana', 'sans-serif'">XML</span><span style="font-family: 宋体">格式），我们还能找到更高效更优雅的方法</span>—<span style="font-family: 宋体">利用</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象为我们组装字符串。下面这段代买组装一个长度为</span><span style="font-family: 'Verdana', 'sans-serif'">950015</span><span style="font-family: 宋体">的字符串仅须耗时</span><span style="font-family: 'Verdana', 'sans-serif'">0.890</span><span style="font-family: 宋体">秒。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">利用</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">DOM</span><span style="font-family: 宋体; font-size: 9pt">对象组装信息</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 0.890</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var xmlDoc;&nbsp;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">if (browserType == BROWSER_IE) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlDoc = new ActiveXObject("Msxml.DOMDocument");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">else {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlDoc = document.createElement("DOM");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var root = xmlDoc.createElement("root");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i = 0; i &lt; 50000; i++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var node = xmlDoc.createElement("data");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (browserType == BROWSER_IE) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.text = "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.innerText = "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root.appendChild(node);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">xmlDoc.appendChild(root);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">if (browserType == BROWSER_IE) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str = xmlDoc.xml;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">else {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str = xmlDoc.innerHTML;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">避免</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的内存泄漏。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">关于</span><span style="font-family: 'Verdana', 'sans-serif'">IE</span><span style="font-family: 宋体">中</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的内存泄露是一个常常被开发人员忽略的问题。然而它带来的后果却是非常严重的！它会导致</span><span style="font-family: 'Verdana', 'sans-serif'">IE</span><span style="font-family: 宋体">的内存占用量持续上升，并且浏览器的整体运行速度明显下降。对于一些泄露比较严重的网页，甚至只要刷新几次，运行速度就会降低一倍。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">比较常见的内存泄漏的模型有&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'"><a href="http://birdshome.cnblogs.com/archive/2006/05/28/IE_MemoryLeak.html"><span style="font-family: 宋体; color: windowtext; text-decoration: none; text-underline: none">循环引用</span></a></span><span style="font-family: 宋体">模型&#8221;、&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'"><a href="http://birdshome.cnblogs.com/archive/2006/06/01/ClosureReferences.html"><span style="font-family: 宋体; color: windowtext; text-decoration: none; text-underline: none">闭包函数</span></a></span><span style="font-family: 宋体">模型&#8221;和&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">插入顺序模型&#8221;</span><span style="font-family: 'Verdana', 'sans-serif'">,</span><span style="font-family: 宋体">对于前两种泄漏模型，我们都可以通过在网页析构时解除引用的方式来避免。而对于&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">插入顺序模型&#8221;则需要通过改变一些惯有的编程习惯的方式来避免。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">有关内存泄漏的模型的更多介绍可以通过</span><span style="font-family: 'Verdana', 'sans-serif'">Google</span><span style="font-family: 宋体">很快的查到，本文不做过多的阐述。不过，这里我向您推荐一个可用于查找和分析网页内存泄露的小工具</span>—<span style="font-family: 'Verdana', 'sans-serif'">Drip</span><span style="font-family: 宋体">，目前的较新版本是</span><span style="font-family: 'Verdana', 'sans-serif'">0.5</span><span style="font-family: 宋体">，下载地址是</span><span style="font-family: 'Verdana', 'sans-serif'">http://outofhanwell.com/ieleak/index.php</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">复杂页面的分段装载和初始化</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">对系统当中某些确实比较复杂而又不便使用</span><span style="font-family: 'Verdana', 'sans-serif'">IFrame</span><span style="font-family: 宋体">的界面，我们可以对其实施分段装载。例如对于多页标签的界面，我们可以首先下载和初始化多页标签的默认页，然后利用</span><span style="font-family: 'Verdana', 'sans-serif'">AJAH</span><span style="font-family: 宋体">（</span><span style="font-family: 'Verdana', 'sans-serif'">asynchronous JavaScript and HTML</span><span style="font-family: 宋体">）技术来异步的装载其他标签页中的内容。这样就能保证界面可以在第一时间首先展现给用户。把整个复杂界面的装载过程分散到用户的操作过程当中。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">利用</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">压缩网络流量。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">除了上面提到的这些代码级的改良之外，我们还可以利用</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">来有效的降低网络流量。目前常见的主流浏览器已经全部支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">算法，我们往往只需要编写少量的代码就可以支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">了。例如在</span><span style="font-family: 'Verdana', 'sans-serif'">J2EE</span><span style="font-family: 宋体">中我们可以在</span><span style="font-family: 'Verdana', 'sans-serif'">Filter</span><span style="font-family: 宋体">中通过下面的代码来判断客户端浏览器是否支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">算法，然后根据需要利用</span><span style="font-family: 'Verdana', 'sans-serif'">java.util.zip.GZIPOutputStream</span><span style="font-family: 宋体">来实现</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">的输出。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">判断浏览器对</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">GZIP</span><span style="font-family: 宋体; font-size: 9pt">支持方式的代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">private static String getGZIPEncoding(HttpServletRequest request) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;String acceptEncoding = request.getHeader("Accept-Encoding");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;if (acceptEncoding == null) return null;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;acceptEncoding = acceptEncoding.toLowerCase();</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;if (acceptEncoding.indexOf("x-gzip") &gt;= 0) return "x-gzip";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;if (acceptEncoding.indexOf("gzip") &gt;= 0) return "gzip";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;return null;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">一般而言，</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">对于</span><span style="font-family: 'Verdana', 'sans-serif'">HTML</span><span style="font-family: 宋体">、</span><span style="font-family: 'Verdana', 'sans-serif'">JSP</span><span style="font-family: 宋体">的压缩比可以达到</span><span style="font-family: 'Verdana', 'sans-serif'">80%</span><span style="font-family: 宋体">左右，而它造成的服务端和客户端的性能损耗几乎是可以忽略的。结合其他因素，支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">的网站有可能为我们节约</span><span style="font-family: 'Verdana', 'sans-serif'">50%</span><span style="font-family: 宋体">的网络流量。因此</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">的使用可以为那些网络环境不是特别好的应用带来显著的性能提升。使用</span><span style="font-family: 'Verdana', 'sans-serif'">Http</span><span style="font-family: 宋体">的监视工具</span><span style="font-family: 'Verdana', 'sans-serif'">Fiddler</span><span style="font-family: 宋体">可以方便的检测出网页在使用</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">前后的通讯数据量。</span><span style="font-family: 'Verdana', 'sans-serif'">Fiddler</span><span style="font-family: 宋体">的下载地址是</span><span style="font-family: 'Verdana', 'sans-serif'">http://www.fiddlertool.com/fiddler/</span></p>
<p style="text-align: left; margin: 15.6pt 0cm" class="MsoNormal" align="left"><span style="font-family: 宋体">关于</span><span style="font-family: 'Verdana', 'sans-serif'">Web</span><span style="font-family: 宋体">应用的性能优化其实是一个非常大的话题。本文由于篇幅有限，只能涉及其中的几个细节，并且也无法将这些细节的优化方式全面的展现给大家。期望本文能够引起大家对</span><span style="font-family: 'Verdana', 'sans-serif'">Web</span><span style="font-family: 宋体">应用尤其是客户端性能优化的充分重视。毕竟服务端编程技巧已为大家熟知多年，在服务端挖掘性能的潜力已经不大了。而在客户端的方法改进往往能够得到令人惊奇的性能提升。</span></p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/344056.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-02-11 15:23 <a href="http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PopCap James Gwwertzman：植物大战僵尸成功秘诀大揭秘</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/23/335986.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sat, 23 Oct 2010 11:44:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/23/335986.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/335986.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/23/335986.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/335986.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/335986.html</trackback:ping><description><![CDATA[以&#8220;迎接万亿移动应用大时代&#8221;为主题，本年度最受瞩目的移动开发者盛会——&#8220;2010中国移动开发者大会&#8221;在北京新云南皇冠酒店隆重开幕。此次大会由CSDN和创新工场联合主办，来自移动领域国内外知名的运营商、平台商、手机终端厂商、应用开发者和投资者等汇聚一堂，共同探讨移动互联网的发展趋势，分享产品研发与运营的成功秘诀。
<p>在10月22日下午的&#8220;走向海外分论坛&#8221;分论坛中，PopCap游戏公司亚太区总裁James Gwertzman发表了主题为《《植物大战僵尸》成功的秘密》的精彩演讲。</p>
<p style="text-align: center"><img alt="" src="http://images.csdn.net/20101022/James%20Gwertzman.jpg" /></p>
<p style="text-align: center">PopCap游戏公司亚太区总裁James Gwertzman</p>
<p>对于植物大战僵尸成功秘诀，James Gwertzman总结了以下几点：</p>
<p>第一点：设计的游戏必须要有创新。仅把别人的游戏直接搬过来虽然也会成功，但是永远没有办法做成最好的游戏，最好的游戏永远都是原创的、创新的。</p>
<p>第二点：要不断进行完美。设计的游戏要让每种不同类型的人测试这个游戏，去适应不同人群。</p>
<p>第三点：游戏发布后，要不断更新。成功游戏往往会经常更新，植物大战僵尸每三个月会更新一次。</p>
<p>第四点：同时需要充分利用社会网络，要把社会网络和游戏联在一起，这样可以影响游戏的销售情况。</p>
<p>第五点：游戏支持的设备也很重要，对于小开发商必须支持一系列设备。</p>
<p>第六点：最开始游戏要是免费的。免费游戏很容易被嵌入到一些设备。</p>
<p><strong>附演讲实录：</strong></p>
<p>James&nbsp; Gwwertzman：大家好，今天给大家谈一谈我们PopCap的经验，我们想问一下大家有多少人玩过，所以这样我就不介绍这个游戏了，我们PopCaP目前为止最成功的游戏也是卖得最快的游戏，我想介绍我们怎么放在移动端上应用，首先给大家举一个例子这里面是我们原来这个游戏获得的一些奖项大家可以非常受欢迎，不仅在PC机上在手机上也是有很多流行比用iPhoen其他设备玩这个游戏，比如说在中国我最喜欢这个视频是从哈尔滨学生传过来，他们做了一个小视频模拟了这个游戏，可以在土豆或者其他上面可以看到，这个可以看到哈尔滨冰雪节的时候，哈尔滨每天雪雕艺术展，我们还有iPhoen版本，大家有多少人在iPhoen或者Ipad上，这个是我最喜欢的版本，最有意思，最好玩和在PC机或者iPhoen，Ipad是最有意思最好玩的。</p>
<p>当我们推出iPhoen版本我们当时第一周销售超过100万美金，然后对于我们PopCaP公司还有包括iPhoen都是历史记录，这个是我们销售在亚洲销售情况，可以看到红色这个是大中华区，绿色是澳大利亚，中间这一部分我们在中国iPhoen版本比其他国家都要多这个是很少见，我们从来没有在中国卖游戏赚钱这是第一次，我们在iPhoen上面比日本，新加坡，还有其他的一些都是远远超过的，增长速度也是不断的在增加，在我们销售平台上增加，所以越来越设备销售出去越来越多，iPhoen4当几周以前上个月北京国内推出iPhoen4，中国成为第二个全球的PPZ国家第一是美国，第二是中国，iPhoen4越来越多会下载我们这个植物大战僵尸。</p>
<p>我想谈一下如何能做一个成功的游戏，当然要开发一个好的游戏，但是不仅如此要开发一个很好游戏其实并不容易，我们PopCaP有几方面做得比较好，首先第一个就是你必须要能够创新，不能说把别人的游戏直接搬过来放过来就成功，当然抄别人东西可能风险比较小，可能做得还不错但是永远没有办法做到最好游戏，最好的游戏永远都是原创，创新的，和别的游戏不一样的，这个不是我们PopCaP游戏，这个仍然也是做得非常好的游戏，现在有很多不同版本，不同方面，第一要承担创新的风险，第二当你有想法要不断完美，我觉得对于开发者有很多问题，就是说还没有把这个游戏完全做得非常好，还做得比较好，或者还不错，还不是完美就推出我们这个游戏花三年时间准备，第二年我们CEO说这个不错，很好游戏赶紧推出我们说不行，我们还不是很完美游戏，到第三年我们才觉得这个游戏是趋于完美了，我们CEO当时说原来第二年的时候说要把这个游戏推出，他说这是他做得最大一个错误，因为第三年可以把这个游戏进一步雕琢，这个是一个屏幕截图，这个是我们第一个版本，我们当时第一个版本05年就是这个样子的，所以可以看到我们第一个版本叫种种子，就是说你把你植物种到土里面，这些都是植物逐渐一点点长大，植物长大开始和坏人作战，右边可以看到是种植工，开发人员他们当时设计就是原来植物和害虫打仗不是和僵尸这个是游戏原形，当时这个游戏一点都不好玩，种种子还要等着这个种子长大这个过程和烦人，你看到你种种子下去逐渐长大作战，种下种子马上要跟它进行坏人作战，从原形我们发现他的问题在哪里这个是06年第二版本植物大战僵尸，我给大家看一下这个游戏。</p>
<p>可以看到谁能认出这个图标，我们上面说在一个暖箱当中，在早期版本上你必须选择某一个卡，把它放到这个卡当中，像这样，你选择你的卡片以后会随即选择哪个卡来玩。</p>
<p>比如说是随即来选这个植物的，然后你要等他卡出现在上面，这个也不是很有意思，为什么？它太随即了，比如说我现在想在这边再种一个种植我不能种了，得等到卡出现才能种，它太随即了。所以大家可以看到这是早期一个版本。所以在这个版本06年版本当时告诉我们就是这种随机性现在卡片，随即你选什么也不是很有意思，不好玩，我们永远不是有一个设计的文件，我们不在纸上写下来游戏是怎么设计出来，你不知道你只有玩的时候才知道这个话游戏好玩不好玩，你只有做完以后玩以下才知道这个游戏意思没意思，早期版本向日葵，僵尸最初分几行种植这是我们原形还有很多东西我们早期是没有考虑是后期添加，这个也是我们从早期版本学到这个是另外一个版本，是我们07年一个版本，07年我们这个游戏其实看起来已经很好玩，背景跟现在差不多，包括格子分布，僵尸形状基本定下来，有很多已经定下来还有最主要一个问题，大家可以看到我不知道大家能不能看到这些植物图表，向日葵是100分，豆荚也是100分，对新玩家玩这个不了解这个经济学，不了解就是说为什么你要先种很多向日葵再种豆荚打僵尸刚开始玩家可能会挣很多钱，有100块钱他想我是选向日葵还是豆荚先玩家会建立这样一个的在家门口都是种的豆荚，最后肯定会失败不了解这个游戏，所以当时我们设计师想如何解决这样的问题，如何教给新玩家为什么先种向日葵，这个对于很多游戏设计师第一答案你教他，如果玩家不懂你要加一个说明，但是我觉得这个设计是不好的，说明就是修整你设计当中存在的漏洞，但是这个并不是最好的解决方法，所以他们所做我们的设计师就是说你只能，你某些区域只能种向日葵不能种豆荚，最后我们提出解决方案把价格调整以下，向日葵是50分，豆荚是100分，新玩家会被你带领种很多的向日葵，通过小阳光挣很多钱才能花钱种豆荚等等，这个就是很好的解决了这样一个问题，所以你看到是一个很小的变化，但是影响整个游戏对新玩家的布局。</p>
<p>对于高级玩家对于其他游戏很熟悉这个你没有什么问题，因为你已经了解了就是先种向日葵再种豆荚，只有随便玩一玩，普通玩家不了解这里面的情况，另外一点我们设计其实目标是针对所有人，大人，小孩，男女等等，你必须找所有人进行测试，我们当时用我们老婆或者女朋友玩这个游戏，所有人都发现这样一个问题，我们自己监测的时候没有任何问题，但是有些人从来没有玩过游戏，觉得这个游戏太难，你设计游戏要让每一个不同类型人测试你这个游戏，这个最新版本是我们花四年时间，是09年版本，我们最初是05年设计出来，大家可以看到是我们最终出来的情况，可以看到价格还有其他很多方面都定下来，你不能够急于求成有很多东西要花很多时间雕琢才能达到精品，我这个笔记本里面有植物大战僵尸十多不同版本，我们一点一点来雕琢完善，第二开发出来很好游戏必须做一个很好手机游戏，像原来我们在电脑上游戏是不一样，如果你在智能手机开发出来游戏还要考虑很多其他因素，对于手机游戏来说首先第一个必须要有一个直观控制，特别是在触屏方式，你设置用户界面是非常关键，如果UI觉得不好玩，没有直接沟通等等，这样没有做好，要有一个直接控制，要调整你这个游戏，或者你把这个游戏来设计，比如说给大家举一个例子，左边是一个在电脑上PC机上的版本，右边是iPhoen版本，可以看到首先第一点就是它的按纽在iPhoen上按纽大很多，iPhoen本身很小，屏幕本身很小，按纽必须比较大用户才能按到，而且很容易能够看到，僵尸脑袋大很多，大了20%，这样用户很容易看到这是那种僵尸，我们还把UI转边上，整个下面一个集成表，我们从右下角挪到中间上面，非常小的改变使它适合IPhone，我们当时有很多设计，在IPhone上面我们使它更加简化而且符合多种平面要求，可以看到右下角不同的iPhoen的UI，所以你对你的游戏不断调整才能做出成功的游戏。</p>
<p>第三点就是必须要不断更新你要不管是3G，2G等等，要跟上，然后成功游戏往往会经常更新，我们植物大战僵尸每三个月更新一次，有些公司频率会更高一些，比如说愤怒鸟这个游戏每两周更新一次，他们也不收钱，你买这个游戏一次每两周都可以更新一次，没有什么问题，这个游戏不断进行更新，人们不断玩不断告诉他们朋友，所以这个愤怒鸟在游戏当中一直是排名前十位，不断更新随着技术不断进展，比如说iPhoen也出现，Android也出现了，技术可能变化速度更快，必须要准备好，不仅仅开发完了这个游戏就是一劳永逸了，是要不断的投入。</p>
<p>还是回到前面这个图，如果你游戏正确你销售会一直增加，我们卖出这个拷贝已经很多了，跟刚开始推出这个游戏已经有很多版本被销售出去，所以大家不要想你这个游戏只卖一个月就完蛋了，如果是一个好的游戏一直会保证一个非常好的销售，所以你要对这个游戏一直进行投资，我们要听取玩家意见，把他融入到我们游戏设计里面去，同时我们需要充分利用社会网络，我们要把社会网络和我们的游戏联在一起，这样可以会影响我们游戏的一个销售，我们看一下一个游戏大家玩过在脸谱上的一个游戏，是一个非常有名的游戏是他的一个改编版本这个就是iPhoen的版本，时间并不是特别长，一般来说都是排第五，第六iPhoen游戏，我们就是把它加上了，我们需要从iPhoen游戏当中登录我们脸谱的一个游戏，可以游戏上玩这个游戏可以得到一个比较高的分数，可以把比较高的分数放到脸谱上，这样一个变化影响是什么，这里是我们销售的一个结果，就是在我们加上脸谱内容以后，在我们加上脸谱的连接性以后，可以看到很多人会在iPhoen上购买游戏，因为他们是从脸谱上了解到这个游戏的，而且我们的销售量也是有了很大的增加，可以看到这个销售量就是在我们加入社交网络之前相比我们销售收入已经增加了两到三倍。</p>
<p>那么我们可以一次性购买iPhoen的游戏，然后可以利用我们的模式规模更多一些更新版本，所以可以看到社会的网络，我认为是相当重要，而且他也会推动我们下一轮网络游戏的一个发展。比如说现在在日本，现在最大的市场是移动社交网络，美国和中国也会很快追上来，我们开发游戏是要把游戏和社交网络结合在一起，因为我们认为这个是一个非常大的成长空间，我们大家应该更多考虑一下社交网络，再现网络或者是社交网络联在一起，另外是我们支持设备也是相当重要，对于小开发商我们必须支持一系列设备，对于PopCaP也是一个非常大的挑战，比如说现在我也没有一个对Android还没有一个很好的融合，比如说之前我们也发现要支持很多设备是非常难的，我们有很多技术但是我们还需要做很多调查测试这是一个非常大的挑战如果我们游戏可以在更多设备商玩我们就会增加一个收入。</p>
<p>后面我会讲一下PLANTS。这个就是其中一个离子2我认为PLANTS这个版本要比我们的PC版本还有移动手机版本要好得多，将来我们会更多开发一些用于PLANTS方面游戏，我们会设计一些图标，比如说我的孩子只有6岁他特别喜欢我这个IPAD，因为他喜欢用我的IPAD玩游戏，我们家里面也有PC和其他设备但是他总是喜欢通过IPAD玩游戏也就证明这方面市场是非常大。</p>
<p>我们看一下在亚洲和中国，我没有必要告诉F2P是一个很好的模式，我们知道免费玩游戏是一个非常好的模式，当然在美国销售游戏是比较好的模式，在中国我想免费玩游戏是非常好的模式，特别是在中国，或者在亚洲我们发现很多游戏是免费玩的一种模式，如果是能够免费玩的话，如果是这种模式游戏DRM很容易被破解，但是在IPAD可以有，别的地方没有，所以这个DRM五问题一定是非常重要的，另外一个就是有大量的OEM嵌入机会，游戏是免费游戏很容易被嵌入到一些设备，可以获得一些许可一些成本，可以获得一些许可费，同时比如说我们看一下软件商城，这里就是一个IPhone上一个嵌入一个应用我们需要够一些它也是非常好，我们点击一下我们就可以进行采购，我想就是每个人都曾经用过这样一些界面我们知道可能有两到三十个软件，这样模式可能会很快流行起来，你是否愿意花更多时间玩那些你认为可以玩的那些游戏吗，对于用户来说可能会首先购买一个游戏，如果这个游戏是免费，我想问题不会特别大，如果游戏刚开始是免费，也许他们会愿意花一些钱买一些工具，所以大家一定要采用这种模式，最开始游戏是免费的，我不知道有多少人知道PopCaP我们在很多平台上是非常成功，我们有PC，还有在手机，还有在脸谱上等等我们都特别好的游戏的应用软件。</p>
<p>我们希望能够把所有这些平台整合一起，我知道这是一个移动开发者大会，当然这个移动游戏是非常好的，如果这个移动游戏能够和其他平台结合在一起，比如说和我们的网络游戏，PC游戏或者是社交网络联在一起将会更好，如果能够整合所有平台的话，我们的游戏会变得特别强大。</p>
<p>我还有一些关于几个游戏的一些例子，我也会给大家展示一些示范。接下来给大家介绍我们PVZD的一些游戏，然后我们会进入问答环节，我们做植物大战僵尸我们最重要这个游戏一定要好玩，关于PVZ这个游戏，不知道大家是否熟悉这个游戏，在美国就是我们有4月1日愚人节我们喜欢在办公室玩游戏，我们喜欢玩这个PVZ，我们也喜欢在4月1日玩植物大战僵尸游戏我们可以看到，比如说我们会骗别人说我们有一个最新版本最好的植物大战僵尸游戏美国人下载，结果不是，每个人都被骗了。我们有一个内部工具，玩家可以在上面加上他们的一些评论，他们可能会有一些不同评论可能说最好的PVZ版本有些人会说我们会用这个，或者我们怎么杀死圣诞老人僵尸如果你玩的话你会发现它特别有意思。这个就是愚人节的版本，很多人都说根本不好，这个游戏根本不能玩，很多人会问到底出了什么问题，当然这个是一个游戏是一个愚人节版本，同时我们还有一个另外一个僵尸游戏，这个游戏也是来欺骗别人的，大家可以看到也是特别有意思的。我不知道我们还有多长时间，但是现在我想我们应该回答一下大家的问题，如果大家有问题我们可以提问一下。</p>
<p>他问的问题在我们说到免费版本，我们是通过广告赚钱还是通过在线游戏，通过工具来赚钱呢？我们答案就是第二种情况，游戏当中广告说实话并不是很成功，比如说每年我们都听到这样的一些说到游戏当中加广告是非常好的模式，实际上我们这个模式我们也是用十年时间但是从来没有成功，我想就是你让用户为这个工具花钱的话，可能会更加成功，因为觉得花这个钱是为他自己花的，所以我的答案就是第二种模式。</p>
<p>他是一个评论PopCaP是一个如果让人们为这个工具花钱，我们会有一个免费模式，应该成为一个社会网络的游戏，比如说我们做的第一个游戏，这个游戏在脸谱是可以玩的，因为脸谱是一个社交网络我们可以和朋友，一起竞争玩这个游戏，可以拿到一个非常好的分数，他是一个一个非常简单在线模式，也就是说你所要想的就是要获得最高的分数，使劲玩获得很多分数很多人在这方面愿意花很多钱玩这个游戏，这个游戏每年也是变得越来越复杂，可以看到这个游戏就是和最开始我们这个游戏推出和6个月之前我们发现每个用户在上面花钱跟我们游戏推出开始的时候比这个钱是之前的4到5倍，我们有很多方法改善我们的游戏，更新我们的游戏，很多人讲到AP测试就是说我们应该做不同的测试然后选择最好的方法，通过他可以对我们游戏进行提高但是我们可以提高10%到20%，如果我们加入一些新特点，我们能够非常快的推动这个游戏的一个推广，如果你分数非常高这个游戏会说祝贺你，因为你发现我们的月亮石，你是否愿意买，这个玩家会觉得是一个珍贵的宝石，所以他们会用他们免费货币买，当然如果你没有网上虚拟货币可以用真钱买我们的宝石。</p>
<p>当然并不会改变我们的多层的一个平台，很多人非常喜欢这样一种模式，比如说有很多人会尝试这样一个游戏，然后会反复玩，如果我们能够尝试不同的东西的话，可能会帮助你生成更多的收入非常感谢。</p>
<p><strong>提问：</strong>我有两个问题，你讲到PopCaP我们会进入社交网络游戏不仅仅是手机游戏，我中国有一个网络开发商他们已经创建了一个在线的PVZ游戏版本他，他可以在任何浏览器上使用，我的第一个问题就是他很容易被复制，很容易被复制到中国来。所以可能会影响PopCaP在中国的收入，那么您的看法是什么呢？</p>
<p><strong>James&nbsp; Gwwertzman：</strong>就是对于这种山寨游戏我们是非常关注，比如说中国很多山寨游戏我们都知道，有的时候我们会提起上诉，当然就是用法律手段是一种方法，我们都知道PopCaP这个游戏有的时候需要花很多时间才能开发出来好的，很多山寨游戏并不是特别好，总的来说用户都不喜欢那些山寨游戏因为我们总是要听看这个PPS论坛上用户意见这并不是真的我们不喜欢这个游戏，是山寨版本给了我们一个希望，用户新的真的版本，真的东西，真的品牌，我们能够提供一个真正的PVZ游戏如果很有意思我们会占据优势，当然要花很多时间，最开始游戏要花四年时间，要建立一个在线游戏当然要花很长时间，我们最终会推出这样一个在线游戏，我们竞争对手并不应该是这种山寨游戏因为他们的质量太差了，我们真正竞争对手的并不是山寨开发商，我们最大的竞争对手是我们自己，很多人喜欢以前版本我们要把他吸引到再现游戏版本上来说的话，对我来说这是一个很大的挑战，当然如果我们花很长时间开发出非常好在线游戏丰富它的内容我们排名还要考前，人们一直想要尝试愿意玩他们这个游戏，我们希望我们能够开发出特别好的游戏，而且一直进行更新。</p>
<p>我想就是中国可能和国际市场有一些不同，在中国我们有几个非常大的社区，比如说人人，QQ我们知道最初版本是脸谱是一个原创版本，但是PVZiPhoen版本，他们也有一些功能可以很脸谱朋友联一起，但是这个人人还有QQ上的朋友，现在人们喜欢通过山寨版本的脸谱和自己的朋友联合，实际上就是我们也有一个版本就是通过iPhoen可以跟人人联在一起，我们还没有在人人上启动一个功能，但是我们特别重视中国的社交网络比我们跟人人，开心，QQ都进行过跟踪，脸谱不是中国本土网络，在中国就是这样一些市场必须是本土化的，所以我们也希望PopCaP一些游戏能够实现本土化。</p>
<p>你最近是在中国市场上，它能不能用在SNS比如说人人网络上我们现在是出版了它的实验版将来大家可能会看到。</p>
<p><strong>提问：</strong>第一就是你如何平衡它的时间和进展，你刚才说你前面植物僵尸是花四年时间不断雕琢，那么你四年肯定花了很多时间金钱等等，如果成功了没有问题，但是如果你四年以后还是失败怎么办。</p>
<p>第二个问题你如何比如说像EA你觉得他们是你的竞争对手吗？</p>
<p><strong>James&nbsp; Gwwertzman：</strong>第一个问题如果我们花四年时间做游戏如果失败怎么办，比如说花了很多时间精力，对于我们就是快点失败，如果失败就会快一点，这个游戏不会一直投入，然后发展到失败，这个原形就是我们可能过了两周觉得这个游戏不是很有意思，但是我们没有说完全放弃，我们要看它有没有意思，再改进，如果说你这个想法有意思只需要改进可能花三年，我们花了6个月就知道这是一个很好的游戏，如果这个游戏过六周没有意思过了三年也没有意思我们PopCaP有很多游戏没有上市，我们推出很多游戏可能是很多游戏都是从来没有出过他的摇篮当中，你看到都是成功的游戏我们会很快决定，所以对于成本和质量来说往往是有关系，我们CEO说我们每两年推出一个游戏，一个成功的游戏的话，我们做的时候是非常好，每两年只要能有一个游戏成功就没有问题，但是及时这样都很难但是我们不可能一年推出十个游戏，所有都是很一般的游戏，所以游戏好还是不好，得好不好，是不是所有的平台的多挣钱，PC挣这么多钱，iPhoen每一个平台设备都能挣钱所以一个非常伟大的&nbsp; 游戏，根据这个游戏开发出一个不同的系列。</p>
<p><strong>提问：</strong>我想问一下你对于在线多玩家游戏是什么看法。</p>
<p><strong>James&nbsp; Gwwertzman：</strong>这个问题中国现在就是做PC游戏越来越少，我觉得全球范围之内也是这样，PopCaP也是单一玩家游戏会越来越少，将来我们可以看到社交游戏在线游戏，网上游戏等等，网上游戏有很多优势，所以我觉得每个游戏PopCaP有一个网络特性，社交特性，我们现在设计游戏是针对每个人的，所以我们植物大战僵尸也是这样，我们希望将来能够添加我们社交特色社交网络，对于中国更是这样，我们上海有80人团队做中国游戏开发，比如说一个月之前在韩国我们宣布了一个新产品叫PopCaPW是第一个自由在线多玩家PopCaP游戏，有一个超级祖玛四个人多万家2玩祖玛游戏这个是祖玛游戏最有意思一个版本，我们在韩国现在推出了，将来我们有可能把它带到中国市场，我们现在正在开发这种多玩家在线游戏，但是不仅仅是PC，我们说移动设备，比如说现在我们可以看到Android等等，我们觉得多设备，界面也是非常有潜力，非常感谢大家。</p>
文章来自：http://mobile.csdn.net/n/20101022/280798.html
<img src ="http://www.blogjava.net/freeman1984/aggbug/335986.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-23 19:44 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/23/335986.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何防止少量的代码修改导致的全用例测试</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/19/335508.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 18 Oct 2010 16:18:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/19/335508.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/335508.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/19/335508.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/335508.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/335508.html</trackback:ping><description><![CDATA[<span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">&nbsp; </span></span></span></span></span></span></span></span></span></span>
<div><span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;一个关于移动的项目，现在做了快两年了，项目越来越大，其中有的表数据加上历史数据都到10亿级别，由于这两年团队成员流动大，导致代码越来臃肿，前期项目代码的管理不善，除了较大的版本，一般的小修小改都不经过代码评审，本地测试通过后，直接hotfix，有时候很顺利，但是偶尔导致较大问题，有时候甚至影响客户使用，导致公司亏损。现在领导发现问题就直接骂工程部，导致现在每当有一点点修改，工程部都要求AQ按照测试用进行全用例测试，测试非常的不易，光是功能测试几乎5个测试人员一天时间，还要兼容几乎所有浏览器（ie6~8,火狐，遨游，TT，360，google,搜狗）。工作量巨大。没办法现在我们的做法如下：<br />
<br />
<br />
</span></span></span></span></span></span></span></span></span></span></div>
<div><span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">1 &nbsp;&nbsp;&nbsp;&nbsp; 加强代码的版本控制，对每次代码的修改，都直接联系到个人，代码的修改都要写修改说明，包括：修改内容，修改前效果，修改后效果，对其他接口或功能的影响，回滚策略，测试用例。<br />
<br />
</span></span></span></span></span></span></span></span></span></span></div>
<div><span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">2 &nbsp;&nbsp;&nbsp;&nbsp; 代码评审：代码评审的标准我们也在不断修改完善，过一段时都会对评审标准进行评审。评审前参会人员都会拿到 上一步相关人员写的修改说明，会前2小时阅读，会中，有相关人员对代码进行流程讲解，并进行效果演示，评审内容包括，代码评审（是否符合代码评审标准），效果评审（是否达到产品需求效果），用例评审(是否可以覆盖当前修改)，回滚评审（出错后是否可以及时的回滚到前一版本）。<br />
<br />
</span></span></span></span></span></span></span></span></span></span></div>
<div><span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">3 &nbsp;&nbsp;&nbsp;&nbsp; 总结每期评审结果，必要时间进行讨论，提出问题：包括项目中遇到的难题，和大家对评审的看法，总结经验，并对公认的技术问题进行归类，由对此熟悉的人员（架构师，开发经理，个人）在周一进行技术讲解（我们是每月2次的技术培训，没有公共话题的情况下，如果有人想分享个人经验的话，可提前准备，现在为了鼓励大家，根据培训效果，对培训讲解人是有偿的，奖励多少不公开，会中很活跃，一般不会刻意打断你，除非公共话题，这一点我是比较喜欢，每天都会去翻大量的文章，书籍去了解话题）。<br />
<br />
</span></span></span></span></span></span></span></span></span></span></div>
<div><span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">4 和绩效挂钩，这一点大家都不喜欢啊，不过没办法，领导意思，每次上线都搞得心里惶惶的。<br />
<br />
</span></span></span></span></span></span></span></span></span></span></div>
<div><span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; 这些工作我们做了半年，也是有成效，有时候评审会叫上工程部的人来看，工程部也承认我们的工作，也不怎么要求全用例了，但是好多都慢慢形式化，包括评审，主要还是有时候项目特别紧，大家都加班加点干项目，为了上线，项目都改了好几个版本，还没评审一次，结果可想而知。有时候也想过自动化测试，但是离开了人为的控制任然问题多多啊，主要是自动化测试这方便经验不足。<br />
<br />
</span></span></span></span></span></span></span></span></span></span></div>
<div><span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不知道大家在开发大型项目的过程中，都是如何保证产品质量的，主要是如何在项目比较将紧的情况下防止全用例测试，不要说你们每次修改都全用例测试，都是绿灯才上线，全用例测试对我们来说那简直是要命啦，也不要说刚招聘的一个新人他写的代码你就放心不用测试评审。<br />
<br />
</span></span></span></span></span></span></span></span></span></span></div>
<div><span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我个人认为是可以避免少量修改导致的全用例测试的，主要的问题就是修改带出来的新问题，如何防止修改老问题带出新问题，个人认为有以下因素导致：人的积极性，人的责任心，人的上进心。人的积极性需要领导层共同解决，如何在紧张的项目下给员工舒适的环境和心情，人的责任心和上进心是就是自己的素养，不管多么没意思的工作你是否愿意去做好，还有就是你是否愿意提高你的技能来防止这些问题。 &nbsp;但是这每一点都不是嘴上说说就能做好的。</span></span></span></span></span></span></span></span></span></span></div>
<div><span style="font-size: 14pt"><span style="font-family: 宋体"><span style="font-family: 新宋体"><span style="font-family: Arial"><span style="font-size: 12pt"><span style="font-size: 12pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 12pt"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;</span></span></span></span></span></span></span></span></span></span></div>
<img src ="http://www.blogjava.net/freeman1984/aggbug/335508.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-19 00:18 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/19/335508.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>加速Javascript：DOM操作优化</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/17/335395.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sun, 17 Oct 2010 15:53:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/17/335395.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/335395.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/17/335395.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/335395.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/335395.html</trackback:ping><description><![CDATA[<p>原文：《Speeding up JavaScript: Working with the DOM》</p>
<p>作者： KeeKim Heng, Google Web Developer</p>
<p>在我们开发互联网富应用（RIA）时，我们经常写一些javascript脚本来修改或者增加页面元素，这些工作最终是DOM——或者说文档对象模型——来完成的，而我们的实现方式会影响到应用的响应速度。</p>
<p>DOM操作会导致浏览器重解析(reflow)，这是浏览器的一个决定页面元素如何展现的计算过程。直接修改DOM，修改元素的CSS样式，修改浏览器的窗口大小，都会触发重解析。读取元素的布局属性比如offsetHeithe或者offsetWidth也会触发重解析。重解析需要花费计算时间，因此重解析触发的越少，应用就会越快。</p>
<p>DOM操作通常要不就是修改已经存在的页面上的元素，要不就是创建新的页面元素。下面的4种优化方案覆盖了修改和创建DOM节点两种方式，帮助你减少触发浏览器重解析的次数。</p>
<p>方案一：通过CSS类名切换来修改DOM</p>
<p>&nbsp;</p>
<p>这个方案让我们可以一次性修改一个元素和它的子元素的多个样式属性而只触发一次重解析。</p>
<p>需求：</p>
<p>（emu注：原文作者写到这里的时候脑子显然短路了一下，把后面的Out-of-the-flow DOM Manipulation模式要解决的问题给摆到这里来了，不过从示范代码中很容易明白作者真正想描述的问题，因此emu就不照翻原文了）</p>
<p>我们现在需要写一个函数来修改一个超链接的几个样式规则。要实现很简单，把这几个规则对应的属性逐一改了就好了。但是带来的问题是，每修改一个样式属性，都会导致一次页面的重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function selectAnchor(element) {&nbsp;&nbsp; <br />
&nbsp; element.style.fontWeight = 'bold';&nbsp;&nbsp; <br />
&nbsp; element.style.textDecoration = 'none';&nbsp;&nbsp; <br />
&nbsp; element.style.color = '#000';&nbsp;&nbsp; <br />
}&nbsp; <br />
function selectAnchor(element) {<br />
&nbsp; element.style.fontWeight = 'bold';<br />
&nbsp; element.style.textDecoration = 'none';<br />
&nbsp; element.style.color = '#000';<br />
} </p>
<p>解决方案</p>
<p>要解决这个问题，我们可以先创建一个样式名，并且把要修改的样式规则都放到这个类名上，然后我们给超链接添加上这个新类名，就可以实现添加几个样式规则而只触发一次重解析了。这个模式还有个好处是也实现了表现和逻辑相分离。</p>
<p>view plaincopy to clipboardprint?<br />
.selectedAnchor {&nbsp;&nbsp; <br />
&nbsp; font-weight: bold;&nbsp;&nbsp; <br />
&nbsp; text-decoration: none;&nbsp;&nbsp; <br />
&nbsp; color: #000;&nbsp;&nbsp; <br />
}&nbsp;&nbsp; <br />
&nbsp; <br />
function selectAnchor(element) {&nbsp;&nbsp; <br />
&nbsp; element.className = 'selectedAnchor';&nbsp;&nbsp; <br />
}&nbsp; <br />
.selectedAnchor {<br />
&nbsp; font-weight: bold;<br />
&nbsp; text-decoration: none;<br />
&nbsp; color: #000;<br />
}</p>
<p>function selectAnchor(element) {<br />
&nbsp; element.className = 'selectedAnchor';<br />
}</p>
<p>&nbsp;方案二：在非渲染区修改DOM</p>
<p>（emu注：作者在这里再次脑子短路，把DocumentFragment DOM Generation模式的介绍提前到这里来了，emu只好再次发挥一下）<br />
上一个方案解决的是修改一个超链接的问题，当一次需要对很多个超链接进行相同修改的时候，这个方案就可以大显身手了。</p>
<p>需求</p>
<p>需求是这样的，我们要写一个函数来修改一个指定元素的子元素中所有的超链接的样式名（className）属性。要实现很简单，我们可以通过遍历每个超链接并且修改它们的样式名来完成任务。但是带来的问题就是，每修改一个超链接都会导致一次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function updateAllAnchors(element, anchorClass) {&nbsp;&nbsp; <br />
&nbsp; var anchors = element.getElementsByTagName('a');&nbsp;&nbsp; <br />
&nbsp; for (var i = 0, length = anchors.length; i &lt; length; i ++) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchors[i].className = anchorClass;&nbsp;&nbsp; <br />
&nbsp; }&nbsp;&nbsp; <br />
}&nbsp; <br />
function updateAllAnchors(element, anchorClass) {<br />
&nbsp; var anchors = element.getElementsByTagName('a');<br />
&nbsp; for (var i = 0, length = anchors.length; i &lt; length; i ++) {<br />
&nbsp;&nbsp;&nbsp; anchors[i].className = anchorClass;<br />
&nbsp; }<br />
}<br />
&nbsp;</p>
<p>解决方案</p>
<p>要解决这个问题，我们可以把被修改的指定元素从DOM里面移除，再修改所有的超链接，然后在把这个元素插入回到它原来的位置上。为了完成这个复杂的操作，我们可以先写一个可重用的函数，它不但移除了这个DOM节点，还返回了一个把元素插回到原来的位置的函数。</p>
<p>view plaincopy to clipboardprint?<br />
/**&nbsp; <br />
&nbsp;* Remove an element and provide a function that inserts it into its original position&nbsp; <br />
&nbsp;* @param element {Element} The element to be temporarily removed&nbsp; <br />
&nbsp;* @return {Function} A function that inserts the element into its original position&nbsp; <br />
&nbsp;**/&nbsp; <br />
function removeToInsertLater(element) {&nbsp;&nbsp; <br />
&nbsp; var parentNode = element.parentNode;&nbsp;&nbsp; <br />
&nbsp; var nextSibling = element.nextSibling;&nbsp;&nbsp; <br />
&nbsp; parentNode.removeChild(element);&nbsp;&nbsp; <br />
&nbsp; return function() {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; if (nextSibling) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parentNode.insertBefore(element, nextSibling);&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; } else {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parentNode.appendChild(element);&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />
&nbsp; };&nbsp;&nbsp; <br />
}&nbsp; <br />
/**<br />
&nbsp;* Remove an element and provide a function that inserts it into its original position<br />
&nbsp;* @param element {Element} The element to be temporarily removed<br />
&nbsp;* @return {Function} A function that inserts the element into its original position<br />
&nbsp;**/<br />
function removeToInsertLater(element) {<br />
&nbsp; var parentNode = element.parentNode;<br />
&nbsp; var nextSibling = element.nextSibling;<br />
&nbsp; parentNode.removeChild(element);<br />
&nbsp; return function() {<br />
&nbsp;&nbsp;&nbsp; if (nextSibling) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parentNode.insertBefore(element, nextSibling);<br />
&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parentNode.appendChild(element);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; };<br />
} </p>
<p>有了上面这个函数，现在我们就可以在一个不需要解析渲染的元素上面修改那些超链接了。这样只在移除和插入元素的时候各触发一次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function updateAllAnchors(element, anchorClass) {&nbsp;&nbsp; <br />
&nbsp; var insertFunction = removeToInsertLater(element);&nbsp;&nbsp; <br />
&nbsp; var anchors = element.getElementsByTagName('a');&nbsp;&nbsp; <br />
&nbsp; for (var i = 0, length = anchors.length; i &lt; length; i ++) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchors[i].className = anchorClass;&nbsp;&nbsp; <br />
&nbsp; }&nbsp;&nbsp; <br />
&nbsp; insertFunction();&nbsp;&nbsp; <br />
}&nbsp; <br />
function updateAllAnchors(element, anchorClass) {<br />
&nbsp; var insertFunction = removeToInsertLater(element);<br />
&nbsp; var anchors = element.getElementsByTagName('a');<br />
&nbsp; for (var i = 0, length = anchors.length; i &lt; length; i ++) {<br />
&nbsp;&nbsp;&nbsp; anchors[i].className = anchorClass;<br />
&nbsp; }<br />
&nbsp; insertFunction();<br />
}<br />
&nbsp;</p>
<p>方案三：一次性的DOM元素生成</p>
<p>这个方案让我们创建一个元素的过程只触发一次重解析。在创建完元素以后，先进行所有需要的修改，最后才把它插入到DOM里面去就可以了</p>
<p>需求</p>
<p>需求是这样的，实现一个函数，往一个指定的父元素上插入一个超链接元素。这个函数要同时可以设置这个超链接的显示文字和样式类。我们可以这样做：创建元素，插入到DOM里面，然后设置相应的属性。这就要触发3次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function addAnchor(parentElement, anchorText, anchorClass) {&nbsp;&nbsp; <br />
&nbsp; var element = document.createElement('a');&nbsp;&nbsp; <br />
&nbsp; parentElement.appendChild(element);&nbsp;&nbsp; <br />
&nbsp; element.innerHTML = anchorText;&nbsp;&nbsp; <br />
&nbsp; element.className = anchorClass;&nbsp;&nbsp; <br />
}&nbsp; <br />
function addAnchor(parentElement, anchorText, anchorClass) {<br />
&nbsp; var element = document.createElement('a');<br />
&nbsp; parentElement.appendChild(element);<br />
&nbsp; element.innerHTML = anchorText;<br />
&nbsp; element.className = anchorClass;<br />
}<br />
&nbsp;</p>
<p>解决方案</p>
<p>很简单，我们只要把插入元素这个操作放到最后做，就可以只进行一次重解析了。</p>
<p>view plaincopy to clipboardprint?<br />
function addAnchor(parentElement, anchorText, anchorClass) {&nbsp;&nbsp; <br />
&nbsp; var element = document.createElement('a');&nbsp;&nbsp; <br />
&nbsp; element.innerHTML = anchorText;&nbsp;&nbsp; <br />
&nbsp; element.className = anchorClass;&nbsp;&nbsp; <br />
&nbsp; parentElement.appendChild(element);&nbsp;&nbsp; <br />
}&nbsp; <br />
function addAnchor(parentElement, anchorText, anchorClass) {<br />
&nbsp; var element = document.createElement('a');<br />
&nbsp; element.innerHTML = anchorText;<br />
&nbsp; element.className = anchorClass;<br />
&nbsp; parentElement.appendChild(element);<br />
} </p>
<p>不过，要是我们想要插入很多个超链接到一个元素里面的话，那么这个做法还是有问题：每插入一个超链接还是要触发一次重解析。下一个方案可以解决这个问题。</p>
<p>方案四：通过文档片段对象（DocumentFragment）创建一组元素</p>
<p>这个方案允许我们创建并插入很多个元素而只触发一次重解析。要实现这点需要用到所谓的文档片段对象（DocumentFragment）。我们先在DOM之外创建一个文档片段对象（这样它也就不需要解析和渲染），然后我们在文档片段对象中创建很多个元素，最后我们把这个文档片段对象中所有的元素一次性放到DOM里面去，只触发一次重解析。</p>
<p>需求</p>
<p><br />
我们要写一个函数，往一个指定的元素上面增加10个超链接。如果我们简单的直接插入10个超链接到元素上面，就会触发10次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function addAnchors(element) {&nbsp;&nbsp; <br />
&nbsp; var anchor;&nbsp;&nbsp; <br />
&nbsp; for (var i = 0; i &lt; 10; i ++) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchor = document.createElement('a');&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchor.innerHTML = 'test';&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; element.appendChild(anchor);&nbsp;&nbsp; <br />
&nbsp; }&nbsp;&nbsp; <br />
}&nbsp; <br />
function addAnchors(element) {<br />
&nbsp; var anchor;<br />
&nbsp; for (var i = 0; i &lt; 10; i ++) {<br />
&nbsp;&nbsp;&nbsp; anchor = document.createElement('a');<br />
&nbsp;&nbsp;&nbsp; anchor.innerHTML = 'test';<br />
&nbsp;&nbsp;&nbsp; element.appendChild(anchor);<br />
&nbsp; }<br />
} </p>
<p>解决方案</p>
<p>要解决这个问题，我们要先创建一个文档片段对象，然后把每个新创建的超链接都插入到它里面去。当我们把文档片段对象用appendChild命令插入到指定的节点时，这个文档片段对象的所有子节点就一起被插入到指定的元素里面，而且只需要触发一次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function addAnchors(element) {&nbsp;&nbsp; <br />
&nbsp; var anchor, fragment = document.createDocumentFragment();&nbsp;&nbsp; <br />
&nbsp; for (var i = 0; i &lt; 10; i ++) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchor = document.createElement('a');&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchor.innerHTML = 'test';&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; fragment.appendChild(anchor);&nbsp;&nbsp; <br />
&nbsp; }&nbsp;&nbsp; <br />
&nbsp; element.appendChild(fragment);&nbsp;&nbsp; <br />
}&nbsp; </p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/emu/archive/2010/03/01/5334583.aspx</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/335395.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-17 23:53 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/17/335395.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Comet：基于 HTTP 长连接的“服务器推”技术</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sun, 17 Oct 2010 15:45:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/335394.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/335394.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/335394.html</trackback:ping><description><![CDATA[<p>Comet：基于 HTTP 长连接的&#8220;服务器推&#8221;技术<br />
2008-06-30 21:31<br />
别： 中级 <br />
周 婷 (zhouting@cn.ibm.com), 软件工程师, IBM 中国软件开发技术实验室</p>
<p>2007 年 8 月 31 日</p>
<p>很多应用譬如监控、即时通信、即时报价系统都需要将后台发生的变化实时传送到客户端而无须客户端不停地刷新、发送请求。本文首先介绍、比较了常用的&#8220;服务器推&#8221;方案，着重介绍了 Comet － 使用 HTTP 长连接、无须浏览器安装插件的两种&#8220;服务器推&#8221;方案：基于 AJAX 的长轮询方式；基于 iframe 及 htmlfile 的流方式。最后分析了开发 Comet 应用需要注意的一些问题，以及如何借助开源的 Comet 框架－pushlet 构建自己的&#8220;服务器推&#8221;应用。<br />
&#8220;服务器推&#8221;技术的应用</p>
<p>&nbsp;请访问 Ajax 技术资源中心，这是有关 Ajax 编程模型信息的一站式中心，包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。&nbsp; <br />
&nbsp;&nbsp; 订阅 Ajax 相关文章和教程的 RSS 提要 <br />
&nbsp;</p>
<p>&nbsp;<br />
&nbsp;<br />
传统模式的 Web 系统以客户端发出请求、服务器端响应的方式工作。这种方式并不能满足很多现实应用的需求，譬如：</p>
<p>监控系统：后台硬件热插拔、LED、温度、电压发生变化； <br />
即时通信系统：其它用户登录、发送信息； <br />
即时报价系统：后台数据库内容发生变化； <br />
这些应用都需要服务器能实时地将更新的信息传送到客户端，而无须客户端发出请求。&#8220;服务器推&#8221;技术在现实应用中有一些解决方案，本文将这些解决方案分为两类：一类需要在浏览器端安装插件，基于套接口传送信息，或是使用 RMI、CORBA 进行远程调用；而另一类则无须浏览器安装任何插件、基于 HTTP 长连接。</p>
<p>将&#8220;服务器推&#8221;应用在 Web 程序中，首先考虑的是如何在功能有限的浏览器端接收、处理信息：</p>
<p>客户端如何接收、处理信息，是否需要使用套接口或是使用远程调用。客户端呈现给用户的是 HTML 页面还是 Java applet 或 Flash 窗口。如果使用套接口和远程调用，怎么和 JavaScript 结合修改 HTML 的显示。 <br />
客户与服务器端通信的信息格式，采取怎样的出错处理机制。 <br />
客户端是否需要支持不同类型的浏览器如 IE、Firefox，是否需要同时支持 Windows 和 Linux 平台。 <br />
&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
基于客户端套接口的&#8220;服务器推&#8221;技术</p>
<p>Flash XMLSocket</p>
<p>如果 Web 应用的用户接受应用只有在安装了 Flash 播放器才能正常运行， 那么使用 Flash 的 XMLSocket 也是一个可行的方案。</p>
<p>这种方案实现的基础是：</p>
<p>Flash 提供了 XMLSocket 类。 <br />
JavaScript 和 Flash 的紧密结合：在 JavaScript 可以直接调用 Flash 程序提供的接口。 <br />
具体实现方法：在 HTML 页面中内嵌入一个使用了 XMLSocket 类的 Flash 程序。JavaScript 通过调用此 Flash 程序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很容易地控制 HTML 页面的内容显示。</p>
<p>关于如何去构建充当了 JavaScript 与 Flash XMLSocket 桥梁的 Flash 程序，以及如何在 JavaScript 里调用 Flash 提供的接口，我们可以参考 AFLAX（Asynchronous Flash and XML）项目提供的 Socket Demo 以及 SocketJS（请参见 参考资源）。</p>
<p>Javascript 与 Flash 的紧密结合，极大增强了客户端的处理能力。从 Flash 播放器 V7.0.19 开始，已经取消了 XMLSocket 的端口必须大于 1023 的限制。Linux 平台也支持 Flash XMLSocket 方案。但此方案的缺点在于：</p>
<p>客户端必须安装 Flash 播放器； <br />
因为 XMLSocket 没有 HTTP 隧道功能，XMLSocket 类不能自动穿过防火墙； <br />
因为是使用套接口，需要设置一个通信端口，防火墙、代理服务器也可能对非 HTTP 通道端口进行限制； <br />
不过这种方案在一些网络聊天室，网络互动游戏中已得到广泛使用。</p>
<p>Java Applet 套接口 </p>
<p>在客户端使用 Java Applet，通过 java.net.Socket 或 java.net.DatagramSocket 或 java.net.MulticastSocket 建立与服务器端的套接口连接，从而实现&#8220;服务器推&#8221;。</p>
<p>这种方案最大的不足在于 Java applet 在收到服务器端返回的信息后，无法通过 JavaScript 去更新 HTML 页面的内容。</p>
<p>&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
基于 HTTP 长连接的&#8220;服务器推&#8221;技术</p>
<p>Comet 简介</p>
<p>浏览器作为 Web 应用的前台，自身的处理功能比较有限。浏览器的发展需要客户端升级软件，同时由于客户端浏览器软件的多样性，在某种意义上，也影响了浏览器新技术的推广。在 Web 应用中，浏览器的主要工作是发送请求、解析服务器返回的信息以不同的风格显示。AJAX 是浏览器技术发展的成果，通过在浏览器端发送异步请求，提高了单用户操作的响应性。但 Web 本质上是一个多用户的系统，对任何用户来说，可以认为服务器是另外一个用户。现有 AJAX 技术的发展并不能解决在一个多用户的 Web 应用中，将更新的信息实时传送给客户端，从而用户可能在&#8220;过时&#8221;的信息下进行操作。而 AJAX 的应用又使后台数据更新更加频繁成为可能。</p>
<p>图 1. 传统的 Web 应用模型与基于 AJAX 的模型之比较&nbsp; <br />
&#8220;服务器推&#8221;是一种很早就存在的技术，以前在实现上主要是通过客户端的套接口，或是服务器端的远程调用。因为浏览器技术的发展比较缓慢，没有为&#8220;服务器推&#8221;的实现提供很好的支持，在纯浏览器的应用中很难有一个完善的方案去实现&#8220;服务器推&#8221;并用于商业程序。最近几年，因为 AJAX 技术的普及，以及把 IFrame 嵌在&#8220;htmlfile&#8220;的 ActiveX 组件中可以解决 IE 的加载显示问题，一些受欢迎的应用如 meebo，gmail+gtalk 在实现中使用了这些新技术；同时&#8220;服务器推&#8221;在现实应用中确实存在很多需求。因为这些原因，基于纯浏览器的&#8220;服务器推&#8221;技术开始受到较多关注，Alex Russell（Dojo Toolkit 的项目 Lead）称这种基于 HTTP 长连接、无须在浏览器端安装插件的&#8220;服务器推&#8221;技术为&#8220;Comet&#8221;。目前已经出现了一些成熟的 Comet 应用以及各种开源框架；一些 Web 服务器如 Jetty 也在为支持大量并发的长连接进行了很多改进。关于 Comet 技术最新的发展状况请参考关于 Comet 的 wiki。</p>
<p>下面将介绍两种 Comet 应用的实现模型。</p>
<p>基于 AJAX 的长轮询（long-polling）方式</p>
<p>如 图 1 所示，AJAX 的出现使得 JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP 请求，JavaScript 响应处理函数根据服务器返回的信息对 HTML 页面的显示进行更新。使用 AJAX 实现&#8220;服务器推&#8221;与传统的 AJAX 应用不同之处在于：</p>
<p>服务器端会阻塞请求直到有数据传递或超时才返回。 <br />
客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后，再次发出请求，重新建立连接。 <br />
当客户端处理接收的数据、重新建立连接时，服务器端可能有新的数据到达；这些信息会被服务器端保存直到客户端重新建立连接，客户端会一次把当前服务器端所有的信息取回。 <br />
图 2. 基于长轮询的服务器推模型&nbsp; <br />
一些应用及示例如 &#8220;Meebo&#8221;, &#8220;Pushlet Chat&#8221; 都采用了这种长轮询的方式。相对于&#8220;轮询&#8221;（poll），这种长轮询方式也可以称为&#8220;拉&#8221;（pull）。因为这种方案基于 AJAX，具有以下一些优点：请求异步发出；无须安装插件；IE、Mozilla FireFox 都支持 AJAX。</p>
<p>在这种长轮询方式下，客户端是在 XMLHttpRequest 的 readystate 为 4（即数据传输结束）时调用回调函数，进行信息处理。当 readystate 为 4 时，数据传输结束，连接已经关闭。Mozilla Firefox 提供了对 Streaming AJAX 的支持， 即 readystate 为 3 时（数据仍在传输中），客户端可以读取数据，从而无须关闭连接，就能读取处理服务器端返回的信息。IE 在 readystate 为 3 时，不能读取服务器返回的数据，目前 IE 不支持基于 Streaming AJAX。</p>
<p>基于 Iframe 及 htmlfile 的流（streaming）方式</p>
<p>iframe 是很早就存在的一种 HTML 标记， 通过在 HTML 页面里嵌入一个隐蔵帧，然后将这个隐蔵帧的 SRC 属性设为对一个长连接的请求，服务器端就能源源不断地往客户端输入数据。</p>
<p>图 3. 基于流方式的服务器推模型&nbsp; <br />
上节提到的 AJAX 方案是在 JavaScript 里处理 XMLHttpRequest 从服务器取回的数据，然后 Javascript 可以很方便的去控制 HTML 页面的显示。同样的思路用在 iframe 方案的客户端，iframe 服务器端并不返回直接显示在页面的数据，而是返回对客户端 Javascript 函数的调用，如&#8220;&lt;script type="text/javascript"&gt;js_func(&#8220;data from server &#8221;)&lt;/script&gt;&#8221;。服务器端将返回的数据作为客户端 JavaScript 函数的参数传递；客户端浏览器的 Javascript 引擎在收到服务器返回的 JavaScript 调用时就会去执行代码。</p>
<p>从 图 3 可以看到，每次数据传送不会关闭连接，连接只会在通信出现错误时，或是连接重建时关闭（一些防火墙常被设置为丢弃过长的连接， 服务器端可以设置一个超时时间， 超时后通知客户端重新建立连接，并关闭原来的连接）。</p>
<p>使用 iframe 请求一个长连接有一个很明显的不足之处：IE、Morzilla Firefox 下端的进度栏都会显示加载没有完成，而且 IE 上方的图标会不停的转动，表示加载正在进行。Google 的天才们使用一个称为&#8220;htmlfile&#8221;的 ActiveX 解决了在 IE 中的加载显示问题，并将这种方法用到了 gmail+gtalk 产品中。Alex Russell 在 &#8220;What else is burried down in the depth's of Google's amazing JavaScript?&#8221;文章中介绍了这种方法。Zeitoun 网站提供的 comet-iframe.tar.gz，封装了一个基于 iframe 和 htmlfile 的 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器，可以作为参考。（请参见 参考资源）</p>
<p>&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
使用 Comet 模型开发自己的应用</p>
<p>上面介绍了两种基于 HTTP 长连接的&#8220;服务器推&#8221;架构，更多描述了客户端处理长连接的技术。对于一个实际的应用而言，系统的稳定性和性能是非常重要的。将 HTTP 长连接用于实际应用，很多细节需要考虑。</p>
<p>不要在同一客户端同时使用超过两个的 HTTP 长连接</p>
<p>我们使用 IE 下载文件时会有这样的体验，从同一个 Web 服务器下载文件，最多只能有两个文件同时被下载。第三个文件的下载会被阻塞，直到前面下载的文件下载完毕。这是因为 HTTP 1.1 规范中规定，客户端不应该与服务器端建立超过两个的 HTTP 连接， 新的连接会被阻塞。而 IE 在实现中严格遵守了这种规定。</p>
<p>HTTP 1.1 对两个长连接的限制，会对使用了长连接的 Web 应用带来如下现象：在客户端如果打开超过两个的 IE 窗口去访问同一个使用了长连接的 Web 服务器，第三个 IE 窗口的 HTTP 请求被前两个窗口的长连接阻塞。</p>
<p>所以在开发长连接的应用时， 必须注意在使用了多个 frame 的页面中，不要为每个 frame 的页面都建立一个 HTTP 长连接，这样会阻塞其它的 HTTP 请求，在设计上考虑让多个 frame 的更新共用一个长连接。</p>
<p>服务器端的性能和可扩展性</p>
<p>一般 Web 服务器会为每个连接创建一个线程，如果在大型的商业应用中使用 Comet，服务器端需要维护大量并发的长连接。在这种应用背景下，服务器端需要考虑负载均衡和集群技术；或是在服务器端为长连接作一些改进。</p>
<p>应用和技术的发展总是带来新的需求，从而推动新技术的发展。HTTP 1.1 与 1.0 规范有一个很大的不同：1.0 规范下服务器在处理完每个 Get/Post 请求后会关闭套接口连接； 而 1.1 规范下服务器会保持这个连接，在处理两个请求的间隔时间里，这个连接处于空闲状态。 Java 1.4 引入了支持异步 IO 的 java.nio 包。当连接处于空闲时，为这个连接分配的线程资源会返还到线程池，可以供新的连接使用；当原来处于空闲的连接的客户发出新的请求，会从线程池里分配一个线程资源处理这个请求。 这种技术在连接处于空闲的机率较高、并发连接数目很多的场景下对于降低服务器的资源负载非常有效。</p>
<p>但是 AJAX 的应用使请求的出现变得频繁，而 Comet 则会长时间占用一个连接，上述的服务器模型在新的应用背景下会变得非常低效，线程池里有限的线程数甚至可能会阻塞新的连接。Jetty 6 Web 服务器针对 AJAX、Comet 应用的特点进行了很多创新的改进，请参考文章&#8220;AJAX，Comet and Jetty&#8221;（请参见 参考资源）。</p>
<p>控制信息与数据信息使用不同的 HTTP 连接</p>
<p>使用长连接时，存在一个很常见的场景：客户端网页需要关闭，而服务器端还处在读取数据的堵塞状态，客户端需要及时通知服务器端关闭数据连接。服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒，然后释放为这个客户端分配的资源，再关闭连接。</p>
<p>所以在设计上，我们需要使客户端的控制请求和数据请求使用不同的 HTTP 连接，才能使控制请求不会被阻塞。</p>
<p>在实现上，如果是基于 iframe 流方式的长连接，客户端页面需要使用两个 iframe，一个是控制帧，用于往服务器端发送控制请求，控制请求能很快收到响应，不会被堵塞；一个是显示帧，用于往服务器端发送长连接请求。如果是基于 AJAX 的长轮询方式，客户端可以异步地发出一个 XMLHttpRequest 请求，通知服务器端关闭数据连接。</p>
<p>在客户和服务器之间保持&#8220;心跳&#8221;信息</p>
<p>在浏览器与服务器之间维持一个长连接会为通信带来一些不确定性：因为数据传输是随机的，客户端不知道何时服务器才有数据传送。服务器端需要确保当客户端不再工作时，释放为这个客户端分配的资源，防止内存泄漏。因此需要一种机制使双方知道大家都在正常运行。在实现上：</p>
<p>服务器端在阻塞读时会设置一个时限，超时后阻塞读调用会返回，同时发给客户端没有新数据到达的心跳信息。此时如果客户端已经关闭，服务器往通道写数据会出现异常，服务器端就会及时释放为这个客户端分配的资源。 <br />
如果客户端使用的是基于 AJAX 的长轮询方式；服务器端返回数据、关闭连接后，经过某个时限没有收到客户端的再次请求，会认为客户端不能正常工作，会释放为这个客户端分配、维护的资源。 <br />
当服务器处理信息出现异常情况，需要发送错误信息通知客户端，同时释放资源、关闭连接。 <br />
Pushlet - 开源 Comet 框架</p>
<p>Pushlet 是一个开源的 Comet 框架，在设计上有很多值得借鉴的地方，对于开发轻量级的 Comet 应用很有参考价值。</p>
<p>观察者模型</p>
<p>Pushlet 使用了观察者模型：客户端发送请求，订阅感兴趣的事件；服务器端为每个客户端分配一个会话 ID 作为标记，事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。</p>
<p>客户端 JavaScript 库</p>
<p>pushlet 提供了基于 AJAX 的 JavaScript 库文件用于实现长轮询方式的&#8220;服务器推&#8221;；还提供了基于 iframe 的 JavaScript 库文件用于实现流方式的&#8220;服务器推&#8221;。</p>
<p>JavaScript 库做了很多封装工作：</p>
<p>定义客户端的通信状态：STATE_ERROR、STATE_ABORT、STATE_NULL、STATE_READY、STATE_JOINED、STATE_LISTENING； <br />
保存服务器分配的会话 ID，在建立连接之后的每次请求中会附上会话 ID 表明身份； <br />
提供了 join()、leave()、subscribe()、 unsubsribe()、listen() 等 API 供页面调用； <br />
提供了处理响应的 JavaScript 函数接口 onData()、onEvent()&#8230; <br />
网页可以很方便地使用这两个 JavaScript 库文件封装的 API 与服务器进行通信。</p>
<p>客户端与服务器端通信信息格式</p>
<p>pushlet 定义了一套客户与服务器通信的信息格式，使用 XML 格式。定义了客户端发送请求的类型：join、leave、subscribe、unsubscribe、listen、refresh；以及响应的事件类型：data、join_ack、listen_ack、refresh、heartbeat、error、abort、subscribe_ack、unsubscribe_ack。</p>
<p>服务器端事件队列管理</p>
<p>pushlet 在服务器端使用 Java Servlet 实现，其数据结构的设计框架仍可适用于 PHP、C 编写的后台客户端。</p>
<p>Pushlet 支持客户端自己选择使用流、拉（长轮询）、轮询方式。服务器端根据客户选择的方式在读取事件队列（fetchEvents）时进行不同的处理。&#8220;轮询&#8221;模式下 fetchEvents() 会马上返回。&#8221;流&#8220;和&#8221;拉&#8220;模式使用阻塞的方式读事件，如果超时，会发给客户端发送一个没有新信息收到的&#8220;heartbeat&#8220;事件，如果是&#8220;拉&#8221;模式，会把&#8220;heartbeat&#8221;与&#8220;refresh&#8221;事件一起传给客户端，通知客户端重新发出请求、建立连接。</p>
<p>客户服务器之间的会话管理</p>
<p>服务端在客户端发送 join 请求时，会为客户端分配一个会话 ID， 并传给客户端，然后客户端就通过此会话 ID 标明身份发出 subscribe 和 listen 请求。服务器端会为每个会话维护一个订阅的主题集合、事件队列。</p>
<p>服务器端的事件源会把新产生的事件以多播的方式发送到每个会话（即订阅者）的事件队列里。</p>
<p>&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
小结</p>
<p>本文介绍了如何在现有的技术基础上选择合适的方案开发一个&#8220;服务器推&#8221;的应用，最优的方案还是取决于应用需求的本身。相对于传统的 Web 应用， 目前开发 Comet 应用还是具有一定的挑战性。</p>
<p>&#8220;服务器推&#8221;存在广泛的应用需求，为了使 Comet 模型适用于大规模的商业应用，以及方便用户构建 Comet 应用，最近几年，无论是服务器还是浏览器都出现了很多新技术，同时也出现了很多开源的 Comet 框架、协议。需求推动技术的发展，相信 Comet 的应用会变得和 AJAX 一样普及。</p>
<p>参考资料 </p>
<p>学习 <br />
developerWorks 文章&#8220; 面向 Java 开发人员的 Ajax: 使用 Jetty 和 Direct Web Remoting 编写可扩展的 Comet 应用程序&#8221;：受异步服务器端事件驱动的 Ajax 应用程序实现较为困难，本文介绍了一种结合使用 Comet 模式和 Jetty 6 Continuations API 的解决方法。 <br />
&#8220;Comet: Low Latency Data for the Browser&#8221;：Alex Russell 是 Dojo Toolkit 的项目主管和 Dojo Foundation 的主席，他在这篇博客文章中提出了 Comet 这个术语。 <br />
&#8220;What else is burried down in the depth&#8217;s of Google&#8217;s amazing JavaScript?&#8221;（Alex Russel，2006 年 2 月）：Alex 在这篇文章里介绍了如何使用&#8220;htmlfile&#8221;ActiveX 控件解决 iframe 请求长连接时 IE 的加载显示问题。 <br />
Comet wiki：提供了很多开源 Comet 框架的链接。 <br />
Jetty：Jetty 是一种开源的基于标准的 Web 服务器，完全使用 Java 语言实现。 <br />
&#8220;Ajax, Comet and Jetty&#8221;（Greg Wilkins，Webtide，2006 年 1 月）：Wilkins 的这份白皮书讨论了扩展 Ajax 连接的 Jetty 架构方法。 <br />
Continuations：了解更多关于 Jetty 的 Continuations 特性的信息。 <br />
&#8220;pushlet&#8221;：开源 comet 框架，使用了观察者模型。浏览器端提供了基于 AJAX 和 iframe 的 JavaScript 库，服务器端使用 Java Servlet。 <br />
&#8220;How to implement COMET with PHP&#8221;：提供的 comet-iframe.tar.gz 使用 iframe/htmlfile 封装了一个 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器。 <br />
&#8220;AFLAX&#8221;：Asynchronous Flash and XML，提供了强大的 Flash、Javascript 库和很多范例。 <br />
developerWorks Ajax 技术资源中心：能找到更多关于 Ajax 技术的文章和教程。 <br />
developerWorks Web 开发技术专区：提供了关于 Web 开发和架构方面的大量文章。 <br />
developerWorks Java 技术专区：提供了关于 Java 编程各个方面的数百篇文章。 <br />
浏览 技术书店，查阅有关本文所述主题以及其他技术主题的书籍。&nbsp; </p>
<p><br />
&nbsp;</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/335394.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-17 23:45 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle 10g SQL 优化再学习</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/10/334235.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sun, 10 Oct 2010 15:52:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/10/334235.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/334235.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/10/334235.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/334235.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/334235.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<p>从8i到10g，Oracle不断进化自己的SQL Tuning智能，一些秘籍级的优化口诀已经失效。<br />
&nbsp;&nbsp; 但我喜欢失效，不用记口诀，操个Toad for Oracle Xpert ，按照大方向舒舒服服的调优才是爱做的事情。</p>
<p>1.Excution Plan<br />
&nbsp;&nbsp;&nbsp;&nbsp; Excution Plan是最基本的调优概念，不管你的调优吹得如何天花乱堕，结果还是要由Excution plan来显示Oracle 最终用什么索引、按什么顺序连接各表，Full Table Scan还是Access by Rowid Index，瓶颈在什么地方。如果没有它的指导，一切调优都是蒙的。</p>
<p><br />
2.Toad for Oracle Xpert<br />
&nbsp;&nbsp;&nbsp; 用它来调优在真的好舒服。Quest 吞并了Lecco后，将它整合到了Toad 的SQL Tunning里面：最清晰的执行计划显示，自动生成N条等价SQL、给出优化建议，不同SQL执行计划的对比，还有实际执行的逻辑读、物理读数据等等一目了然。</p>
<p><br />
3.索引<br />
&nbsp;&nbsp; 大部分的性能问题其实都是索引应用的问题，Where子句、Order By、Group By 都要用到索引。<br />
&nbsp;&nbsp; 一般开发人员认为将索引建全了就可以下班回家了，实则还有颇多的思量和陷阱。</p>
<p>3.1 索引列上不要进行计算<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这是最最普遍的失效陷阱，比如where trunc(order_date)=trunc(sysdate), i+2&gt;4。索引失效的原因也简单，索引是针对原值建的二叉树，你将列值*3/4+2折腾一番后，原来的二叉树当然就用不上了。解决的方法:<br />
　 1.　换成等价语法，比如trunc(order_date) 换成</p>
<p>where order_date&gt;trunc(sysdate)-1 and order_date&lt;trunc(sysdate)+1　 2.&nbsp;&nbsp;&nbsp; 特别为计算建立函数索引</p>
<p>create index Ｉ_XXXX on shop_order(trunc(order_date))&nbsp;&nbsp;&nbsp; 3.&nbsp;&nbsp;&nbsp; 将计算从等号左边移到右边<br />
　这是针对某些无心之失的纠正，把a*2&gt;4　改为a&gt;4/2；把TO_CHAR(zip) = '94002' 改为zip = TO_NUMBER('94002');</p>
<p>3.2 CBO与索引选择性<br />
&nbsp;&nbsp;&nbsp;&nbsp; 建了索引也不一定会被Oracle用的，就像个挑食的孩子。基于成本的优化器(CBO, Cost-Based Optimizer)，会先看看表的大小，还有索引的重复度，再决定用还是不用。表中有100 条记录而其中有80 个不重复的索引键值. 这个索引的选择性就是80/100 = 0.8，留意Toad里显示索引的Selective和Cardinailty。实在不听话时，就要用hints来调教。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 另外，where语句存在多条索引可用时，只会选择其中一条。所以索引也不是越多越好：）</p>
<p>3.3 索引重建<br />
&nbsp;&nbsp;&nbsp;&nbsp; 传说中数据更新频繁导致有20%的碎片时，Oracle就会放弃这个索引。宁可信其有之下，应该时常alter index &lt;INDEXNAME&gt; rebuild一下。</p>
<p>3.4 其他要注意的地方<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不要使用Not，如goods_no != 2，要改为</p>
<p>where goods_no&gt;2 or goods_no&lt;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不要使用is null , 如WHERE DEPT_CODE IS NOT NULL 要改为</p>
<p>WHERE DEPT_CODE &gt;=0;3.5 select 的列如果全是索引列时<br />
&nbsp;&nbsp; 又如果没有where 条件，或者where条件全部是索引列时，Oracle 将直接从索引里获取数据而不去读真实的数据表，这样子理论上会快很多，比如</p>
<p>select order_no,order_time from shop_order where shop_no=4当order_no,order_time,shop_no 这三列全为索引列时，你将看到一个和平时完全不同的执行计划。</p>
<p>3.6 位图索引<br />
&nbsp;&nbsp;&nbsp;&nbsp; 传说中当数据值较少，比如某些表示分类、状态的列，应该建位图索引而不是普通的二叉树索引，否则效率低下。不过看执行计划，这些位图索引鲜有被Oracle临幸的。<br />
&nbsp; </p>
<p><br />
4.减少查询往返和查询的表<br />
这也是很简单的大道理，程序与Oracle交互的成本极高，所以一个查询能完成的不要分开两次查，如果一个循环执行１万条查询的，怎么都快不到哪里去了。</p>
<p>4.1 封装PL/SQL存储过程<br />
　 最高级的做法是把循环的操作封装到PL/SQL写的存储过程里，因为存储过程都在服务端执行，所以没有数据往返的消耗。</p>
<p><br />
4.2 封装PL/SQL内部函数<br />
&nbsp; 有机会，将一些查询封装到函数里，而在普通SQL里使用这些函数，同样是很有效的优化。</p>
<p>4.3 Decode/Case<br />
　 但存储过程也麻烦，所以有case/decode把几条条件基本相同的重复查询合并为一条的用法：</p>
<p>SELECT<br />
&nbsp;COUNT(CASE WHEN price &lt; 13 THEN 1 ELSE null END) low,<br />
&nbsp;COUNT(CASE WHEN price BETWEEN 13 AND 15 THEN 1 ELSE null END) med,<br />
&nbsp;COUNT(CASE WHEN price &gt; 15 THEN 1 ELSE null END) high<br />
FROM products;4.4 一种Where/Update语法</p>
<p>SELECT TAB_NAME　FROM TABLES<br />
WHERE (TAB_NAME,DB_VER) = （( SELECT TAB_NAME,DB_VER)<br />
FROM TAB_COLUMNS WHERE VERSION = 604)</p>
<p>UPDATE EMP<br />
SET (EMP_CAT, SAL_RANGE)<br />
= (SELECT MAX(CATEGORY)FROM EMP_CATEGORIES)<br />
5.其他优化<br />
5.1RowID和ROWNUM<br />
&nbsp;&nbsp;&nbsp;&nbsp; 连Hibernate 新版也支持ROWID了，证明它非常有用。比如号称删除重复数据的最快写法：</p>
<p>DELETE FROM EMP E<br />
WHERE E.ROWID &gt; (SELECT MIN(X.ROWID)<br />
FROM EMP X<br />
WHERE X.EMP_NO = E.EMP_NO);6.终极秘技 - Hints<br />
&nbsp;&nbsp; 这是Oracle DBA的玩具，也是终极武器，比如Oracle在CBO,RBO中所做的选择总不合自己心水时，可以用它来强力调教一下Oracle，结果经常让人喜出望外。<br />
&nbsp;&nbsp; 如果开发人员没那么多时间来专门学习它，可以依靠Toad SQL opmitzer 来自动生成这些提示，然后对比一下各种提示的实际效果。不过随着10g智能的进化，hints的惊喜少了。</p>
<p>7. 找出要优化的Top SQL<br />
&nbsp;&nbsp;&nbsp; 磨了这么久的枪，如果找不到敌人是件郁闷的事情。<br />
&nbsp;&nbsp;&nbsp; 幸亏10g这方面做得非常好。进入Web管理界面，就能看到当前或者任意一天的SQL列表，按性能排序。<br />
&nbsp;&nbsp;&nbsp; 有了它，SQL Trace和TKPROF都可以不用了。</p>
<p><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/calvinxiu/archive/2005/11/15/529756.aspx</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/334235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-10 23:52 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/10/334235.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网管技巧：无法远程桌面连接解决方法 </title><link>http://www.blogjava.net/freeman1984/archive/2010/10/09/334042.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sat, 09 Oct 2010 02:02:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/09/334042.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/334042.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/09/334042.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/334042.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/334042.html</trackback:ping><description><![CDATA[<table style="border-top: #ffffff 17px solid" class="titel" border="0" cellspacing="0" cellpadding="0" width="98%">
    <tbody>
        <tr>
            <td align="center">
            <h1 class="titel">网管技巧：无法远程桌面连接解决方法 </h1>
            </td>
        </tr>
    </tbody>
</table>
<table style="margin: 2px 0px 20px" border="0" cellspacing="0" cellpadding="0" width="560">
    <tbody>
        <tr>
            <td bgcolor="#b1bcc0" height="1"></td>
        </tr>
    </tbody>
</table>
<table style="margin-bottom: 20px" border="0" cellspacing="0" cellpadding="0" width="98%">
    <tbody>
        <tr>
            <td align="center"></td>
        </tr>
    </tbody>
</table>
<table class="p11" border="0" cellspacing="0" cellpadding="0" width="560">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" align="left">
            <p style="text-indent: 2em" class="a14c"><span id="zoom" class="a14c">
            <p style="text-indent: 2em">【赛迪网技术报道】
            <p style="text-indent: 2em">1、检查点击我的电脑-右键-服务中的Terminal Services这个服务是否运行.
            <p style="text-indent: 2em">2、检查我的电脑-右键-属性-远程-是否钩选远程桌面.
            <p style="text-indent: 2em">3、检查系统自带的防火是否开启.如果开启了请关闭.
            <p style="text-indent: 2em">4、默认情况下,远程登录的帐号密码不能为空.一定要设置有密码.(默认情况下这个用户必须设置密码，若没有设置密码就不能在远程登录界面用空密码登录。这是因为已启用了组策略中&#8220;计算机配置&#8221;&#8594;&#8220;安全设置&#8221;&#8594;&#8220;本地策略&#8221;&#8594;&#8220;安全选项&#8221;&#8594;&#8220;帐户：使用空白密码的本地帐户只允许进行控制台登录&#8221;策略，双击，把它改为&#8220;已禁用&#8221;就能用空密码的帐户进行远程登录了。)
            <p style="text-indent: 2em">
            <p style="text-indent: 2em">Terminal Services
            <p style="text-indent: 2em">允许用户以交互方式连接到远程计算机。远程桌面、快速用户切换、远程协助和终端服务器依赖此服务 - 停止或禁用此服务会使您的计算机变得不可靠。要阻止远程使用此计算机，请在&#8220;系统&#8221;属性控制面板项目上清除&#8220;远程&#8221;选项卡上的复选框。
            <p style="text-indent: 2em">C:\WINDOWS\System32\svchost.exe -k termsvcs </p>
            </span></td>
        </tr>
    </tbody>
</table>
文章转自：http://tech.ccidnet.com/art/1084/20090213/1675535_1.html
<img src ="http://www.blogjava.net/freeman1984/aggbug/334042.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-09 10:02 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/09/334042.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让程序向卫星发射一样受控：谨慎在for循环中的使用集合的remove(int index)  </title><link>http://www.blogjava.net/freeman1984/archive/2010/10/01/333617.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 01 Oct 2010 10:59:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/01/333617.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/333617.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/01/333617.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/333617.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/333617.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一段代码引发的惨案&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2010/10/01/333617.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/333617.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-01 18:59 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/01/333617.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2EE开发注意事项</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/01/333614.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 01 Oct 2010 09:40:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/01/333614.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/333614.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/01/333614.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/333614.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/333614.html</trackback:ping><description><![CDATA[<h3><a href="http://kiral.javaeye.com/blog/186456">J2EE开发注意事项</a></h3>
<div class="blog_content"><strong>1.页面展现层</strong> <br />
1.每个input输入框都必须设置maxlength。texaArea没有maxlength这个属性，所以必须使用js来控制用户输入的长度。 <br />
2.对于数据显示列表，必须定义每列的宽度，必须强制截取每列的长度，在TITLE显示每列的全部数据。 <br />
3.必须在用户指定的分辨率下进行测试，如1024*768。 <br />
4.尽量在firefox下做测试，这样能尽量兼容各个浏览器。 <br />
5.页面上的地址原则上写绝对路径。 <br />
6.空间和窗口的大小，尽量使用百分比，而不是像素点。以避免在不同分辨率下界面错位的问题。 <br />
7.对于表格的各列，根据显示的内容，固定该列的宽度。 <br />
<br />
<strong>2.业务逻辑层</strong> <br />
2.1 在获得数据和编辑数据的时候，必须先检查当前数据是否存在，如果不存在，则提示用户。 <br />
2.2 原则上调用service层，不直接调用DAO层。 <br />
2.3 输出数据格式与平台无关，如： 输出JSON的数据格式，这样页面展现层无论是用jsp，swing,flex开发都能使用这些数据。 <br />
<br />
<strong>3.服务展现层</strong> <br />
3.1 对于多条数据库更新操作，使用事务处理。单条数据更新操作不做事务处理。 <br />
3.2 对传入的参数，进行验证，抛出参数异常。 <br />
3.3 抛出用户友好异常。如 当前用户已经存在。 <br />
3.4 尽量抛出uncheck异常，不推荐抛出check异常。 <br />
<br />
<strong>4.数据访问层</strong> <br />
4.1 不涉及任何业务逻辑，只关心数据的操作。如： <br />
不应该提供查询已办任务的方法，应该是通过任务状态进行查询 <br />
<br />
转载自：http://kiral.javaeye.com/blog/186456</div>
<img src ="http://www.blogjava.net/freeman1984/aggbug/333614.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-01 17:40 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/01/333614.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>