<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss">

<channel>
	<title>Here comes the Sun &#187; 手艺</title>
	<atom:link href="http://sunng.info/blog/category/%e6%89%8b%e8%89%ba/feed/" rel="self" type="application/rss+xml" />
	<link>http://sunng.info/blog</link>
	<description>Life ramblings</description>
	<lastBuildDate>Tue, 07 Sep 2010 13:05:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Newly designed front page</title>
		<link>http://sunng.info/blog/2010/09/newly-designed-front-page/</link>
		<comments>http://sunng.info/blog/2010/09/newly-designed-front-page/#comments</comments>
		<pubDate>Tue, 07 Sep 2010 13:05:54 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[css]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=663</guid>
		<description><![CDATA[The last version of my home page was initialized at 2008.9. After two years, the page is completely obsolete, some features were broken due to different reasons. (fanfou.com has been shutdown and twitter was banned). So I just bring you this: The page is extremely simple, without any JavaScript or image. Some CSS3 features have [...]]]></description>
			<content:encoded><![CDATA[<p>The last version of my home page was initialized at 2008.9. After two years, the page is completely obsolete,  some features were broken due to different reasons. (fanfou.com has been shutdown and twitter was banned). </p>
<p>So I just bring you this:<br />
<a href="http://www.flickr.com/photos/40741608@N08/4967665544/" title="screenshot_001 by 贝小塔, on Flickr"><img src="http://farm5.static.flickr.com/4124/4967665544_1b607edbf5.jpg" width="500" height="294" alt="screenshot_001" /></a></p>
<p>The page is extremely simple, without any JavaScript or image. Some CSS3 features have been applied to it, including gradient background, css border radius (also web font will be added when I find a suitable font). </p>
<p>The photo is taken at Expo, outside the  Holland Pavilion. </p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/09/newly-designed-front-page/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>clojure recur</title>
		<link>http://sunng.info/blog/2010/07/clojure-recur/</link>
		<comments>http://sunng.info/blog/2010/07/clojure-recur/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 15:16:01 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[clojure]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/2010/07/clojure-recur/</guid>
		<description><![CDATA[clojure是函数是编程语言，本身没有循环的语法。要实现类似循环的效果，需要用递归来实现。比如计算从1加到n的和这样一个函数： &#40;defn addup &#160; &#160; &#40;&#91;limit&#93; &#40;addup limit 0 0&#41;&#41; &#160; &#160; &#40;&#91;limit current sum&#93; &#160; &#160; &#160; &#160; &#40;if &#40;&#60; limit current&#41; &#160; &#160; &#160; &#160; &#160; &#160; sum &#160; &#160; &#160; &#160; &#160; &#160; &#40;addup limit &#40;+ 1 current&#41; &#40;+ current sum&#41;&#41;&#41;&#41;&#41; 调用 (addup 10) 可以得到55 但是调用 (addup 50000) 不出意外，出现了StackOverflowException， 这是递归典型的错误。 为此，需要进行优化。尾递归优化是指如果递归满足一定条件，编译器可以将递归展开，避免出现栈溢出的问题。这里的条件，就是递归的最后一次调用是否是其本身，比如上面的代码，最后一次操作仍然是addup，即满足尾递归的条件，而如果同样的代码写成： &#40;defn [...]]]></description>
			<content:encoded><![CDATA[<p>clojure是函数是编程语言，本身没有循环的语法。要实现类似循环的效果，需要用递归来实现。比如计算从1加到n的和这样一个函数：</p>
<div class="codecolorer-container lisp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="lisp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defn addup<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span>limit<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>addup limit <span style="color: #cc66cc;">0</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span>limit current sum<span style="color: #66cc66;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&lt;</span> limit current<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sum<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span>addup limit <span style="color: #66cc66;">&#40;</span>+ <span style="color: #cc66cc;">1</span> current<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span>+ current sum<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>调用</p>
<p>(addup 10)</p>
<p>可以得到55</p>
<p>但是调用</p>
<p>(addup 50000)</p>
<p>不出意外，出现了StackOverflowException， 这是递归典型的错误。</p>
<p>为此，需要进行优化。尾递归优化是指如果递归满足一定条件，编译器可以将递归展开，避免出现栈溢出的问题。这里的条件，就是递归的最后一次调用是否是其本身，比如上面的代码，最后一次操作仍然是addup，即满足尾递归的条件，而如果同样的代码写成：</p>
<div class="codecolorer-container lisp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="lisp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defn addup2<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span>limit<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>addup2 limit <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span>limit current<span style="color: #66cc66;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&lt;</span> limit current<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #cc66cc;">0</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span>+ current <span style="color: #66cc66;">&#40;</span>addup2 limit <span style="color: #66cc66;">&#40;</span>+ current <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>最后一个操作是+，不满足尾递归循环，无法进行优化。</p>
<p>clojure默认不进行尾递归优化，需要使用关键字recur来保证优化，把第一段代码写成：</p>
<div class="codecolorer-container lisp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="lisp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defn addup<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span>limit<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>addup limit <span style="color: #cc66cc;">0</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span>limit current sum<span style="color: #66cc66;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&lt;</span> limit current<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sum<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span>recur limit <span style="color: #66cc66;">&#40;</span>+ <span style="color: #cc66cc;">1</span> current<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span>+ current sum<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>社区的解释是，如果程序员在无法进行尾递归优化的代码中使用recur会发生报错，这样有助于他们发现代码中潜在的缺陷。</p>
<p>在第二段代码中使用recur，会得到异常：</p>
<p>java.lang.UnsupportedOperationException: Can only recur from tail position</p>
<p>此外，clojure提供loop函数简化书写：</p>
<div class="codecolorer-container lisp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="lisp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&#40;</span>defn addup3<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span>limit<span style="color: #66cc66;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span>loop <span style="color: #66cc66;">&#91;</span>current <span style="color: #cc66cc;">0</span> sum <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&lt;</span> limit current<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sum<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#40;</span>recur <span style="color: #66cc66;">&#40;</span>+ current <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span>+ current sum<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></div></div>
<p>这种写法同样可以应用尾递归优化而不会导致栈溢出。</p>
<p>The post is brought to you by <a href="http://fedorahosted.org/lekhonee">lekhonee</a> v0</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/07/clojure-recur/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>RPC, Serialization and Schema</title>
		<link>http://sunng.info/blog/2010/06/rpc-serialization-and-schema/</link>
		<comments>http://sunng.info/blog/2010/06/rpc-serialization-and-schema/#comments</comments>
		<pubDate>Sat, 12 Jun 2010 08:16:45 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[sergent]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=591</guid>
		<description><![CDATA[The post is brought to you by lekhonee v0.7 糖果项目的后端用Java编写，我负责service gateway的开发（暂且叫sergent），服务以Java接口+Annotation的形式声明，与Spring集成使用，Java对象被序列化为JSON和XML（通过jackson和castor）与外部系统交互。专门的JSON Schema和XML Schema是可选的，系统交互通过简明的文档和人工确认。 RPC框架是跨进程、跨系统交互的重要工具，RPC框架中又包括远程调用、网络传输和序列化反序列化等等部分。流行的工具包括Facebook的thrift，Google的Protobuf和原先Hadoop项目下的avro。其中thrift包含远程调用、反序列化、网络等等全部的功能。Protobuf本身是一个序列化反序列化库，另有很多第三方RPC实现，avro目前除了序列化和反序列化的功能，也包含了ipc的HTTP Server和SocketServer等实现。在序列化的格式方面，Thrift支持JSON和二进制协议，Protobuf本身仅有二进制支持，但已经存在第三方的其他格式实现。 avro原生支持二进制和JSON格式。 从效率上来说，二进制方式的序列化要比文本方式的快。Google Code上（最近迁往了github）有一个tpc项目（thrift-protobuf-compare），根据这个项目的最新的比较结果（与原先不同）： protobuf成为了三者中耗时最少的框架，之后是thrift和avro，这次avro的耗时甚至超过了文本方式的jackson（主要在反序列化上）。 但是二进制协议通常都需要定义Schema，thrift / protobuf / avro三者各自定义了Schema的格式，没有类似XSD和Json Schema的统一标准，也就是说，当你需要传输一个对象，就要为它编写一个Schema文件。按照通常的习惯，都是先编写Schema，然后通过命令行工具或者自动构建工具来生成Java source。对于新系统还好说，对旧系统这个改造就比较麻烦了。另外，二进制协议不便于调试，所以各个thrift/protobuf/avro先后也都有JSON的实现，在文本的序列化格式上，JSON对XML的优势是全方位的。 所以综合起来，很难说有一种完美的解决方案。二进制协议的效率高，但是改造、编写Schema的代价并不小，还要面对核心Model被绑架到具体框架的风险。文本协议开发简便，不需要Schema，直接POJO就可以序列化和反序列化，但是在时间和空间上都不如二进制的方式。 补充 从tpc项目的结果上看，kryo在时间、空间上都击败了所有对手，而且，kryo的API非常简洁，不需要Schema文件就可以序列化POJO，听起来太完美了，看来以后sergent要借鉴一下的。 补充 2010-06-14 发现avro现在也有ReflectDatumReader和ReflectDatumWriter，可以通过反射内部自动映射生成Schema，可以尝试一下。]]></description>
			<content:encoded><![CDATA[<p>The post is brought to you by <a href="http://fedorahosted.org/lekhonee">lekhonee</a> v0.7</p>
<p>糖果项目的后端用Java编写，我负责service gateway的开发（暂且叫sergent），服务以Java接口+Annotation的形式声明，与Spring集成使用，Java对象被序列化为JSON和XML（通过jackson和castor）与外部系统交互。专门的JSON Schema和XML Schema是可选的，系统交互通过简明的文档和人工确认。</p>
<p>RPC框架是跨进程、跨系统交互的重要工具，RPC框架中又包括远程调用、网络传输和序列化反序列化等等部分。流行的工具包括Facebook的<a href="http://incubator.apache.org/thrift/">thrift</a>，Google的<a href="http://code.google.com/p/protobuf/">Protobuf</a>和原先Hadoop项目下的<a href="http://avro.apache.org/">avro</a>。其中thrift包含远程调用、反序列化、网络等等全部的功能。Protobuf本身是一个序列化反序列化库，另有很多<a href="http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns#RPC_Implementations">第三方RPC实现</a>，avro目前除了序列化和反序列化的功能，也包含了ipc的HTTP Server和SocketServer等实现。在序列化的格式方面，Thrift支持JSON和二进制协议，Protobuf本身<a href="http://code.google.com/p/protobuf/issues/detail?id=82">仅有二进制支持</a>，但已经存在<a href="http://code.google.com/p/protobuf-java-format/">第三方的其他格式实现</a>。 avro原生支持二进制和JSON格式。</p>
<p>从效率上来说，二进制方式的序列化要比文本方式的快。Google Code上（最近迁往了github）有一个<a href="http://wiki.github.com/eishay/jvm-serializers/">tpc项目</a>（thrift-protobuf-compare），根据这个项目的最新的比较结果（与原先不同）：<br />
<img src="http://chart.apis.google.com/chart?chtt=total&#038;chf=c||lg||0||FFFFFF||1||76A4FB||0|bg||s||EFEFEF&#038;chs=700x426&#038;chd=t:3234,4375,4583,5094,5712,6949,7199,7817,9228,9532,11160,11265,12575,12698,13233,14117,14950,16244,17187,23282,28258,31018,37012,43989,61663,74099,113707,141689,218143,225905,227399,227943,228237&#038;chds=0,251061.7483&#038;chxt=y&#038;chxl=0:|woodstox-xstream|fastinfo-xstream|xml%2Fxstream|aalto-xstream|json%2Fgoogle-gson|json%2Fprotobuf|scala%2Fjava-built-in|java-built-in|xml%2Fxstream%2Bc|fastinfo-xstream%2Bc|woodstox-xstream%2Bc|xml%2Fmanual-fastinfo|aalto-xstream%2Bc|hessian|json%2Fjackson-databind|xml%2Fmanual-woodstox|xml%2Fjavolution|json%2Fprotostuff-runtime|avro-generic|json%2Fprotostuff-core|avro|json%2Fjackson-manual|xml%2Fmanual-aalto|thrift-compact|thrift|scala%2Fsbinary|protobuf%2Factivemq%2Balt|protobuf|protobuf%2Fprotostuff-runtime|protobuf%2Fprotostuff-core|kryo|kryo-opt|java-manual&#038;chm=N%20*f*,000000,0,-1,10&#038;lklk&#038;chdlp=t&#038;chco=660000|660033|660066|660099|6600CC|6600FF|663300|663333|663366|663399|6633CC|6633FF|666600|666633|666666&#038;cht=bhg&#038;chbh=6,0,6&#038;nonsense=aaa.png" title="" alt="" /></p>
<p>protobuf成为了三者中耗时最少的框架，之后是thrift和avro，这次avro的耗时甚至超过了文本方式的jackson（主要在反序列化上）。</p>
<p>但是二进制协议通常都需要定义Schema，thrift / protobuf / avro三者各自定义了Schema的格式，没有类似XSD和Json Schema的统一标准，也就是说，当你需要传输一个对象，就要为它编写一个Schema文件。按照通常的习惯，都是先编写Schema，然后通过命令行工具或者自动构建工具来生成Java source。对于新系统还好说，对旧系统这个改造就比较麻烦了。另外，二进制协议不便于调试，所以各个thrift/protobuf/avro先后也都有JSON的实现，在文本的序列化格式上，JSON对XML的优势是全方位的。</p>
<p>所以综合起来，很难说有一种完美的解决方案。二进制协议的效率高，但是改造、编写Schema的代价并不小，还要面对核心Model被绑架到具体框架的风险。文本协议开发简便，不需要Schema，直接POJO就可以序列化和反序列化，但是在时间和空间上都不如二进制的方式。</p>
<p>补充<br />
从tpc项目的结果上看，kryo在时间、空间上都击败了所有对手，而且，kryo的API非常简洁，不需要Schema文件就可以序列化POJO，听起来太完美了，看来以后sergent要借鉴一下的。</p>
<p><strong>补充 2010-06-14</strong><br />
发现avro现在也有ReflectDatumReader和ReflectDatumWriter，可以通过反射内部自动映射生成Schema，可以尝试一下。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/06/rpc-serialization-and-schema/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>ibatis infinite loop when getFirstResultSet</title>
		<link>http://sunng.info/blog/2010/06/ibatis-infinite-loop/</link>
		<comments>http://sunng.info/blog/2010/06/ibatis-infinite-loop/#comments</comments>
		<pubDate>Tue, 08 Jun 2010 14:01:03 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[ibatis]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=587</guid>
		<description><![CDATA[前几天上线后老大发现几台负载非常高，dump线程状态后发现多个线程死循环在同一处，于是发现了ibatis的这个bug： https://issues.apache.org/jira/browse/IBATIS-384 https://issues.apache.org/jira/browse/IBATIS-587 在mysql数据库上，没有结果集时，stmt.getUpdateCount()会返回0，而非-1. ibatis 2.4.3 &#160; private ResultSet getFirstResultSet&#40;StatementScope scope, Statement stmt&#41; throws SQLException &#123; &#160; &#160; ResultSet rs = null; &#160; &#160; boolean hasMoreResults = true; &#160; &#160; while &#40;hasMoreResults&#41; &#123; &#160; &#160; &#160; rs = stmt.getResultSet&#40;&#41;; &#160; &#160; &#160; if &#40;rs != null&#41; &#123; &#160; &#160; &#160; &#160; break; &#160; &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>前几天上线后老大发现几台负载非常高，dump线程状态后发现多个线程死循环在同一处，于是发现了ibatis的这个bug：</p>
<p>https://issues.apache.org/jira/browse/IBATIS-384</p>
<p>https://issues.apache.org/jira/browse/IBATIS-587</p>
<p>在mysql数据库上，没有结果集时，<em>stmt.getUpdateCount()</em>会返回0，而非-1.<br />
ibatis 2.4.3</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color: #000000; font-weight: bold;">private</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aresultset+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">ResultSet</span></a> getFirstResultSet<span style="color: #009900;">&#40;</span>StatementScope scope, <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astatement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Statement</span></a> stmt<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asqlexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">SQLException</span></a> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aresultset+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">ResultSet</span></a> rs <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">boolean</span> hasMoreResults <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">true</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span>hasMoreResults<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; rs <span style="color: #339933;">=</span> stmt.<span style="color: #006633;">getResultSet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>rs <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; hasMoreResults <span style="color: #339933;">=</span> moveToNextResultsIfPresent<span style="color: #009900;">&#40;</span>scope, stmt<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> rs<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">boolean</span> moveToNextResultsIfPresent<span style="color: #009900;">&#40;</span>StatementScope scope, <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astatement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Statement</span></a> stmt<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asqlexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">SQLException</span></a> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">boolean</span> moreResults<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// This is the messed up JDBC approach for determining if there are more results</span><br />
&nbsp; &nbsp; moreResults <span style="color: #339933;">=</span> <span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>moveToNextResultsSafely<span style="color: #009900;">&#40;</span>scope, stmt<span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #009900;">&#40;</span>stmt.<span style="color: #006633;">getUpdateCount</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> moreResults<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">boolean</span> moveToNextResultsSafely<span style="color: #009900;">&#40;</span>StatementScope scope, <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astatement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Statement</span></a> stmt<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asqlexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">SQLException</span></a> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>forceMultipleResultSetSupport<span style="color: #009900;">&#40;</span>scope<span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> stmt.<span style="color: #006633;">getConnection</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getMetaData</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">supportsMultipleResultSets</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> stmt.<span style="color: #006633;">getMoreResults</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span></div></div>
<p>moreResults恒为真，程序出现死循环。</p>
<p>在mybatis 2.5的代码里，这部分已经修改为：</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">boolean</span> moveToNextResultsIfPresent<span style="color: #009900;">&#40;</span>StatementScope scope, <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astatement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Statement</span></a> stmt<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asqlexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">SQLException</span></a> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">boolean</span> moreResults<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// This is the messed up JDBC approach for determining if there are more results</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">boolean</span> movedToNextResultsSafely <span style="color: #339933;">=</span> moveToNextResultsSafely<span style="color: #009900;">&#40;</span>scope, stmt<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">int</span> updateCount <span style="color: #339933;">=</span> stmt.<span style="color: #006633;">getUpdateCount</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; moreResults <span style="color: #339933;">=</span> <span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>movedToNextResultsSafely <span style="color: #339933;">&amp;&amp;</span> <span style="color: #009900;">&#40;</span>updateCount <span style="color: #339933;">==</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//ibatis-384: workaround for mysql not returning -1 for stmt.getUpdateCount()</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>moreResults <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; moreResults <span style="color: #339933;">=</span> <span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>movedToNextResultsSafely <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span>isMultipleResultSetSupportPresent<span style="color: #009900;">&#40;</span>scope, stmt<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> moreResults<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">boolean</span> moveToNextResultsSafely<span style="color: #009900;">&#40;</span>StatementScope scope, <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astatement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Statement</span></a> stmt<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asqlexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">SQLException</span></a> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>isMultipleResultSetSupportPresent<span style="color: #009900;">&#40;</span>scope, stmt<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> stmt.<span style="color: #006633;">getMoreResults</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #008000; font-style: italic; font-weight: bold;">/**<br />
&nbsp; &nbsp;* checks whether multiple result set support is present - either by direct support of the database driver or by forcing it<br />
&nbsp; &nbsp;*/</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">boolean</span> isMultipleResultSetSupportPresent<span style="color: #009900;">&#40;</span>StatementScope scope,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astatement+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">Statement</span></a> stmt<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asqlexception+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">SQLException</span></a> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> forceMultipleResultSetSupport<span style="color: #009900;">&#40;</span>scope<span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> stmt.<span style="color: #006633;">getConnection</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getMetaData</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">supportsMultipleResultSets</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span></div></div>
<p>这部分条件判断实在很极致了。</p>
<p>新的实现当getUpdateResult是0时，moreResults恒为真，这时再进行一个判断，如果是由于isMultipleResultSetSupportPresent为false导致了moveToNextResultsSafely为false，那么实际moreResults应是false</p>
<p>MyBatis 2.5还有一个issue没有解决，离发布还有一些时间，这个问题只好签出新版本代码自己build了</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/06/ibatis-infinite-loop/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	<georss:point>31.2013666 121.6192502</georss:point>	</item>
		<item>
		<title>Maven recipe #0</title>
		<link>http://sunng.info/blog/2010/05/maven-recipe-0/</link>
		<comments>http://sunng.info/blog/2010/05/maven-recipe-0/#comments</comments>
		<pubDate>Sat, 15 May 2010 17:02:26 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[recipe]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=571</guid>
		<description><![CDATA[问题： 多个root pom的dependencyManagement有重复的内容，希望统一管理。 解决： 新建一个空pom.xml，在dependencyManagement中指定这些依赖，如 &#60;project xmlns=&#34;http://maven.apache.org/POM/4.0.0&#34; xmlns:xsi=&#34;http://www.w3.org/2001/XMLSchema-instance&#34; &#160; &#160; xsi:schemaLocation=&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&#34;&#62; &#160; &#160; &#60;modelVersion&#62;4.0.0&#60;/modelVersion&#62; &#160; &#160; &#60;groupId&#62;info.sunng&#60;/groupId&#62; &#160; &#160; &#60;artifactId&#62;root&#60;/artifactId&#62; &#160; &#160; &#60;packaging&#62;pom&#60;/packaging&#62; &#160; &#160; &#60;version&#62;0.0.1-SNAPSHOT&#60;/version&#62; &#160; &#160; &#60;dependencyManagement&#62; &#160; &#160; &#160; &#160; &#60;dependencies&#62; &#160; &#160; &#160; &#160; &#160; &#160; &#60;dependency&#62; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#60;groupId&#62;info.sunng&#60;/groupId&#62; &#160; &#160; &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>问题： 多个root pom的dependencyManagement有重复的内容，希望统一管理。<br />
解决：<br />
新建一个空pom.xml，在dependencyManagement中指定这些依赖，如</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;project</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br />
<span style="color: #009900;">&nbsp; &nbsp; <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;modelVersion<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>4.0.0<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/modelVersion<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>info.sunng<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>root<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;packaging<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>pom<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/packaging<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>0.0.1-SNAPSHOT<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependencyManagement<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependencies<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>info.sunng<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>X<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>0.0.1-SNAPSHOT<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependencies<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependencyManagement<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/project<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>在其他root pom中添加这样的dependencyManagement</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">....<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>info.sunng<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>root<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>0.0.1-SNAPSHOT<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;type<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>pom<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/type<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>import<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
....</div></div>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/05/maven-recipe-0/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	<georss:point>31.203057 121.6174866</georss:point>	</item>
		<item>
		<title>Sunng&#039;s Canvas based Heatmap API</title>
		<link>http://sunng.info/blog/2010/02/sunngs-canvas-based-heatmap-api/</link>
		<comments>http://sunng.info/blog/2010/02/sunngs-canvas-based-heatmap-api/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 07:10:03 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[广告]]></category>
		<category><![CDATA[手艺]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[visualization]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=464</guid>
		<description><![CDATA[Glad to announce my works this morning: A simple heatmap API based on HTML5 canvas. The programming interface is rather simple now. To create such a heatmap, you just new a heatmap object by: &#60;canvas width="300" height="215" id="canv"&#62;&#60;/canvas&#62; heatmap = new HeatMap("canv"); Then read your dataset and push data into the heatmap: heatmap.push(x, y, value); [...]]]></description>
			<content:encoded><![CDATA[<p>Glad to announce my works this morning: A simple heatmap API based on HTML5 canvas.<br />
<a href="http://www.flickr.com/photos/40741608@N08/4347604245/" title="canvas by 贝小塔, on Flickr"><img src="http://farm5.static.flickr.com/4071/4347604245_486bd3a12e_o.jpg" width="300" height="215" alt="canvas" /></a></p>
<p>The programming interface is rather simple now. To create such a heatmap, you just new a heatmap object by:</p>
<pre class="brush:html">
&lt;canvas width="300" height="215" id="canv"&gt;&lt;/canvas&gt;
</pre>
<pre class="brush:javascript">
heatmap = new HeatMap("canv");
</pre>
<p>Then read your dataset and push data into the heatmap:</p>
<pre class="brush:javascript">
heatmap.push(x, y, value);
</pre>
<p>At last, spread the data and get the canvas rendered:</p>
<pre class="brush:javascript">
heatmap.spread();
heatmap.render();
</pre>
<p>Now you got it.</p>
<p>For advanced usage, you can specify the resolution of heatmap by px:</p>
<pre class="brush:javascript">
heatmap = new HeatMap("canv", 2);
</pre>
<p>Large value will gain performance with low image quality.</p>
<p>Also, you can specify a value to define the attenuation value of each px.</p>
<pre class="brush:javascript">
heatmap.spread(5);
</pre>
<p>Finally, there is an option to use your own color schema for heatmap generation.</p>
<pre class="brush:javascript">
heatmap.render(function(value, maxValue){
    var light = value / maxValue * 100;
    return "hsl(20, 75%, "+light+"%)";
});
</pre>
<p>The parameters passed in are current pixel value and max value in whole context.</p>
<p>That&#8217;s all the toolkit. More functionality and options might be added in future. Grab it from my bitbucket page:<br />
<a href="http://bitbucket.org/sunng/daily-coding/src/tip/canvas-heatmap/">http://bitbucket.org/sunng/daily-coding/src/tip/canvas-heatmap/</a></p>
<p>There is a demo page which you can test the api by clicking canvas:<br />
<a href="http://www.flickr.com/photos/40741608@N08/4347650163/" title="canvas-raw by 贝小塔, on Flickr"><img src="http://farm3.static.flickr.com/2733/4347650163_ea740356e4_o.jpg" width="326" height="284" alt="canvas-raw" /></a><br />
then click heatmap button!<br />
<a href="http://www.flickr.com/photos/40741608@N08/4348397874/" title="canvas2 by 贝小塔, on Flickr"><img src="http://farm3.static.flickr.com/2796/4348397874_8ac80b0756_o.jpg" width="314" height="275" alt="canvas2" /></a></p>
<p>This is the new year gift for my readers and my dear friends !</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/02/sunngs-canvas-based-heatmap-api/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
	<georss:point>31.203057 121.6174866</georss:point>	</item>
		<item>
		<title>Suppressing simple-xml&#039;s class attribute</title>
		<link>http://sunng.info/blog/2010/02/suppressing-simple-xmls-class-attribute/</link>
		<comments>http://sunng.info/blog/2010/02/suppressing-simple-xmls-class-attribute/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 07:07:12 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://sunng.info/blog/?p=452</guid>
		<description><![CDATA[Simple-xml is an object-xml serialization and de-serialization framework. It&#8217;s featured by annotation-driven, light-weight and self-contained. In simple-xml, pojos that will be serialized are annotated with @Root, @Element, @Attribute or @Text. The problem is, when handling with inheritance, if the actual type is different from declared type, simple-xml will add a &#8220;class&#8221; attribute for de-serialization consideration. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://simple.sourceforge.net" target="_blank">Simple-xml</a> is an object-xml serialization and de-serialization framework. It&#8217;s featured by annotation-driven, light-weight and self-contained.</p>
<p>In simple-xml, pojos that will be serialized are annotated with @Root, @Element, @Attribute or @Text. The problem is, when handling with inheritance, if the actual type is different from declared type, simple-xml will add a &#8220;class&#8221; attribute for de-serialization consideration. That is, the parser will use this attribute to determine the schema of the xml element. However, this is of no useful when we do not parse xml by simple-xml. And there is also risk that the class attribute exposes our program&#8217;s internal structure.</p>
<p>Take following code as example:</p>
<pre class="brush:java">@Root
public class Response{
    @Element
    private Object entry;

    // getter and setter ...
}

public class OrderItem{
    @Element
    private String name;

    // getter and setter ...
}</pre>
<p>When you generate xml from classes above, you will have the entry element of response with an attribute &#8220;class&#8221;, which value is the qualified class name, like &#8220;package.OrderItem&#8221;.</p>
<p>This is done by simple-xml&#8217;s Strategy interface. By default, the Persister uses TreeStrategy which has an implementation of setElement like:</p>
<pre class="brush:java">/**
 * This is used to attach a attribute to the provided element
 * that is used to identify the class. The attribute name is
 * "class" and has the value of the fully qualified class
 * name for the object provided. This will only be invoked
 * if the object class is different from the field class.
 *
 * @param type this is the declared class for the field used
 * @param value this is the instance variable being serialized
 * @param node this is the element used to represent the value
 * @param map this is used to maintain contextual information
 *
 * @return this returns true if serialization is complete
 */
public boolean setElement(Type type, Object value, NodeMap node, Map map){
    Class actual = value.getClass();
    Class expect = type.getType();
    Class real = actual;
    if(actual.isArray()) {
        real = setArray(expect, value, node);
    }
    if(actual != expect) {
        node.put(label, real.getName());
    }
    return false;
}</pre>
<p>This is where class attributed. So to suppress the attribute, we simply override this method by inherit TreeStrategy. I take a inline class for convenience here.</p>
<pre class="brush:java">Serializer s = new Persister(new TreeStrategy(){
    @Override
    public boolean setElement(Type type, Object value, NodeMap node, Map map){
        return false;
    }
});</pre>
<p>Now it works, however, simple-xml won&#8217;t be able to deserialize xml generated by this modified strategy.</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/02/suppressing-simple-xmls-class-attribute/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	<georss:point>31.203057 121.6174866</georss:point>	</item>
		<item>
		<title>OAuth Step by Step</title>
		<link>http://sunng.info/blog/2010/01/oauth-step-by-step/</link>
		<comments>http://sunng.info/blog/2010/01/oauth-step-by-step/#comments</comments>
		<pubDate>Mon, 04 Jan 2010 15:47:25 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[mashup]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.classicning.com/blog/?p=420</guid>
		<description><![CDATA[最近琢磨OAuth认证方式。OAuth的优点主要在于﻿ 用户不需要直接提供用户名密码给第三方应用，就可以让第三方应用访问受限资源； 资源提供方对第三方应用有更细粒度的控制。 在整个OAuth协议里，生成signature的base string是最容易出错的部分。它由HTTP方法名、URL编码的请求路径和请求的参数表组成。 请求的参数表是除去oauth_signature以外的所有参数，按参数名排序，并进行url转义 def to_signature_key(method, url, data): keys = list(data.keys()) keys.sort() encoded = urllib.quote("&#38;".join([key+"="+data[key] for key in keys])) return "&#38;".join([method, urllib.quote(url, safe="~"), encoded]) 有了这个通用的生成signature base string的方法，以后就可以根据OAuth协议规范按步骤进行。 首先获取Request Token。这一步通常使用资源提供方注册的API Key和API Key Secret def request_token_params(consumer_key, consumer_secret, path, method='GET'): data={} data['oauth_consumer_key']=consumer_key data['oauth_signature_method']='HMAC-SHA1' data['oauth_timestamp']=str(int(time.time())) data['oauth_nonce']=''.join([str(random.randint(0,9)) for i in range(10)]) print data msg = to_signature_key(method, path, data) [...]]]></description>
			<content:encoded><![CDATA[<p>最近琢磨OAuth认证方式。OAuth的优点主要在于﻿</p>
<ul>
<li>用户不需要直接提供用户名密码给第三方应用，就可以让第三方应用访问受限资源；</li>
<li>资源提供方对第三方应用有更细粒度的控制。</li>
</ul>
<p>在整个OAuth协议里，生成signature的base string是最容易出错的部分。它由HTTP方法名、URL编码的请求路径和请求的参数表组成。<br />
请求的参数表是除去oauth_signature以外的所有参数，按参数名排序，并进行url转义</p>
<pre class="brush:python">def to_signature_key(method, url, data):
	keys = list(data.keys())
	keys.sort()
	encoded = urllib.quote("&amp;".join([key+"="+data[key] for key in keys]))
	return "&amp;".join([method, urllib.quote(url, safe="~"), encoded])
</pre>
<p>有了这个通用的生成signature base string的方法，以后就可以根据OAuth协议规范按步骤进行。</p>
<p>首先获取Request Token。这一步通常使用资源提供方注册的API Key和API Key Secret</p>
<pre class="brush:python">def request_token_params(consumer_key, consumer_secret, path, method='GET'):
	data={}
	data['oauth_consumer_key']=consumer_key
	data['oauth_signature_method']='HMAC-SHA1'
	data['oauth_timestamp']=str(int(time.time()))
	data['oauth_nonce']=''.join([str(random.randint(0,9)) for i in range(10)])
	print data

	msg = to_signature_key(method, path, data)
	print msg

	signed = base64.b64encode(hmac.new(consumer_secret+"&amp;", msg, hashlib.sha1).digest())
	print signed
	data['oauth_signature']=signed
	return data

def result2dict(result_string):
	d = {}
	params = res.split('&amp;')
	for p in params:
		d[p.split('=')[0]] = p.split('=')[1]
	return d

conn = httplib.HTTPConnection("www.douban.com", 80)

params = request_token_params(consumer_key, consumer_secret, request_token_path)
conn.request('GET', request_token_path+"?"+urllib.urlencode(params))
res = conn.getresponse().read()
print res
request_token = result2dict(res)
</pre>
<p>这一步可以获得未经认证的Request Token和Request Token Secret。需要注意的细节是在计算hmac签名的时候，即使只有一个Token Secret，仍然需要加上&#8221;&amp;&#8221;</p>
<p>第二步要求用户授权该Request Token，打开浏览器，将用户定向到相应的授权页面，参数为上一步获得的Request Token</p>
<p>第三步，用授权过的Request Token换取Access Token。这一步类似第一步，只是用于签名的token包括API Key Secret和Request Token</p>
<pre class="brush:python">def access_token_params(consumer_key, consumer_secret, oauth_token, oauth_secret, path, method='GET'):
	data={}
	data['oauth_consumer_key']=consumer_key
	data['oauth_signature_method']='HMAC-SHA1'
	data['oauth_timestamp']=str(int(time.time()))
	data['oauth_nonce']=''.join([str(random.randint(0,9)) for i in range(10)])
	data['oauth_token'] = oauth_token

	msg = to_signature_key(method, path, data)
	print msg

	signed = base64.b64encode(hmac.new(consumer_secret+"&amp;"+oauth_secret, msg, hashlib.sha1).digest())
	print signed
	data['oauth_signature']=signed
	return data

params = access_token_params(consumer_key, consumer_secret, request_token['oauth_token'],
	request_token['oauth_token_secret'], access_token_path)
conn.request('GET', access_token_path+"?"+urllib.urlencode(params))
res = conn.getresponse().read()
print res
access_token = result2dict(res)
</pre>
<p>这一步将至少返回Access Token和Access Token Secret，是最终用于访问受限资源的Token。以豆瓣的实现为例，OAuth的相关参数应放在HTTP头里随请求进行发送。</p>
<pre class="brush:python">def oauth_header(consumer_key, consumer_secret, oauth_token, oauth_secret, path, realm):
	data = access_token_params(consumer_key, consumer_secret, oauth_token, oauth_secret, path, method="POST")
	header_string = ','.join([key+'="'+data[key]+'"' for key in data.keys()])
	return 'OAuth realm="'+realm+'",'+header_string

posturl = 'http://api.douban.com/miniblog/saying'

content = """&lt;?xml version='1.0' encoding='UTF-8'?&gt;
&lt;entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/"&gt;
&lt;content&gt;li lei ju le han mei mei&lt;/content&gt;
&lt;/entry&gt;
"""

header = {}
header['Authorization'] = oauth_header(consumer_key, consumer_secret,
		access_token['oauth_token'], access_token['oauth_token_secret'],
		posturl, "http://api.douban.com")
header['Content-Type'] = 'application/atom+xml'
print header

conn.request('POST', posturl, content, header)
res = conn.getresponse().read()

print res

conn.close()
</pre>
<p>在这一步中，用于生成signature base string的url是要访问的受限资源地址，而签名的参数表依然是oauth相关的参数。<br />
生成的Authorization头如下</p>
<pre class="brush:text">Authorization: OAuth realm="http://api.douban.com",
    oauth_nonce="8735717688",
    oauth_timestamp="1262613619",
    oauth_consumer_key="0bc081a01168b263234184e0343a1729",
    oauth_signature_method="HMAC-SHA1",
    oauth_token="5fb836c37543ad691f28a44a5fcb083b",
    oauth_signature="jk6p5qaXVPrGQctSzpO5jjYHfDk="
</pre>
<p>用这个头就可以在一定的时间内访问所有授权范围内的受限资源。</p>
<p>代码是ugly了一些，不过应该相对易于理解吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2010/01/oauth-step-by-step/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<georss:point>31.203057 121.6174866</georss:point>	</item>
		<item>
		<title>Java嵌入式数据库的速度对比</title>
		<link>http://sunng.info/blog/2009/12/java%e5%b5%8c%e5%85%a5%e5%bc%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%84%e9%80%9f%e5%ba%a6%e5%af%b9%e6%af%94/</link>
		<comments>http://sunng.info/blog/2009/12/java%e5%b5%8c%e5%85%a5%e5%bc%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%84%e9%80%9f%e5%ba%a6%e5%af%b9%e6%af%94/#comments</comments>
		<pubDate>Thu, 24 Dec 2009 08:09:41 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[db]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://www.classicning.com/blog/?p=375</guid>
		<description><![CDATA[Yan的APIKEY一直是用嵌入式的数据库存储的，最初使用的是hsqldb，最近又添加了H2和Derby的支持，基本上囊括了所有开源的Java嵌入式数据库。实现多了自然需要挑选、比较一下。 数据库特性的比较，H2的网站上有很好的Matrix，一目了然 http://www.h2database.com/html/features.html#comparison 关于速度的比较，今天做了一个简单的测试。 分别从derby / H2 / hsqldb中取出10 、100、1000条数据，循环100000次，比较耗时，如下： 三者的速度差距非常明显，hsqldb远快于其他两个。 而在10、100、1000条记录的索引上查询，并取出指定记录呢，同样是100000次，如下： 再索引上查询，速度受记录数量的影响非常微弱了。但是hsqldb还是远快于其他二者，有趣的是derby的速度要略微快于H2. 根据这样的结果，在Yan的应用中，hsqldb还是最理想的实现。]]></description>
			<content:encoded><![CDATA[<p>Yan的APIKEY一直是用嵌入式的数据库存储的，最初使用的是hsqldb，最近又添加了H2和Derby的支持，基本上囊括了所有开源的Java嵌入式数据库。实现多了自然需要挑选、比较一下。</p>
<p>数据库特性的比较，H2的网站上有很好的Matrix，一目了然</p>
<p>http://www.h2database.com/html/features.html#comparison</p>
<p>关于速度的比较，今天做了一个简单的测试。</p>
<p>分别从derby / H2 / hsqldb中取出10 、100、1000条数据，循环100000次，比较耗时，如下：</p>
<p><img class="alignnone" src="http://farm3.static.flickr.com/2665/4210754380_5cb4d7b0a8_o.png" alt="" width="376" height="394" /></p>
<p>三者的速度差距非常明显，hsqldb远快于其他两个。</p>
<p>而在10、100、1000条记录的索引上查询，并取出指定记录呢，同样是100000次，如下：</p>
<p><img class="alignnone" src="http://farm3.static.flickr.com/2716/4210754396_e52acc7e69_o.png" alt="" width="376" height="394" /></p>
<p>再索引上查询，速度受记录数量的影响非常微弱了。但是hsqldb还是远快于其他二者，有趣的是derby的速度要略微快于H2.</p>
<p>根据这样的结果，在Yan的应用中，hsqldb还是最理想的实现。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2009/12/java%e5%b5%8c%e5%85%a5%e5%bc%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%84%e9%80%9f%e5%ba%a6%e5%af%b9%e6%af%94/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
	<georss:point>31.203057 121.6174866</georss:point>	</item>
		<item>
		<title>在RHEL4上搭建Python/Lighttpd/FastCGI环境</title>
		<link>http://sunng.info/blog/2009/11/%e5%9c%a8rhel4%e4%b8%8a%e6%90%ad%e5%bb%bapythonlighttpdfastcgi%e7%8e%af%e5%a2%83/</link>
		<comments>http://sunng.info/blog/2009/11/%e5%9c%a8rhel4%e4%b8%8a%e6%90%ad%e5%bb%bapythonlighttpdfastcgi%e7%8e%af%e5%a2%83/#comments</comments>
		<pubDate>Fri, 27 Nov 2009 10:28:50 +0000</pubDate>
		<dc:creator>Sunng</dc:creator>
				<category><![CDATA[手艺]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[lighttpd]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.classicning.com/blog/?p=346</guid>
		<description><![CDATA[在一台赤裸裸的RHEL4上部署web.py程序，一切从几乎是从零开始。以下操作均以root用户操作。 1. 安装MySQL数据库 下载安装MySQL wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.41-linux-i686-glibc23.tar.gz/from/http://mirror.services.wisc.edu/mysql/ 解压，按照INSTALL文件说明进行安装，不多赘述 2. 安装Python环境 下载Python源码 wget http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tar.bz2 解压，编译安装，不需要特殊操作。 下载Easy_install wget http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11-py2.6.egg 安装 sh setuptools-0.6c11-py2.6.egg 安装相关Packages easy_install DBUtils easy_install flup easy_install web.py 安装mysql-python mysql-python包不能用easy_install安装，手动下载 wget http://downloads.sourceforge.net/project/mysql-python/mysql-python-test/1.2.3b1/MySQL-python-1.2.3b1.tar.gz?use_mirror=softlayer 加压，编辑site.cfg 指定mysql_config的路径，注意是新安装的mysql路径 mysql_config=/usr/local/mysql/bin/mysql_config 编译、安装 python setup.py build python setup.py install 声明libmysqlclient路径 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/mysql/lib 3. 安装服务器环境 下载安装fastcgi头文件 wget http://www.fastcgi.com/dist/fcgi.tar.gz 解压，默认编译安装 下载安装PCRE wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.00.tar.bz2 解压，默认编译安装 下载lighttpd wget [...]]]></description>
			<content:encoded><![CDATA[<p>在一台赤裸裸的RHEL4上部署web.py程序，一切从几乎是从零开始。以下操作均以root用户操作。</p>
<h2>1. 安装MySQL数据库</h2>
<p><strong>下载安装MySQL</strong><br />
<em>wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.41-linux-i686-glibc23.tar.gz/from/http://mirror.services.wisc.edu/mysql/</em><br />
解压，按照INSTALL文件说明进行安装，不多赘述</p>
<h2>2. 安装Python环境</h2>
<h3>下载Python源码</h3>
<p><em>wget http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tar.bz2</em><br />
解压，编译安装，不需要特殊操作。</p>
<h3>下载Easy_install</h3>
<p><em>wget http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11-py2.6.egg</em><br />
安装<br />
<em>sh setuptools-0.6c11-py2.6.egg</em></p>
<h3>安装相关Packages</h3>
<p><em>easy_install DBUtils<br />
easy_install flup<br />
easy_install web.py</em></p>
<h3>安装mysql-python</h3>
<p>mysql-python包不能用easy_install安装，手动下载<br />
<em>wget http://downloads.sourceforge.net/project/mysql-python/mysql-python-test/1.2.3b1/MySQL-python-1.2.3b1.tar.gz?use_mirror=softlayer</em><br />
加压，编辑site.cfg<br />
指定mysql_config的路径，注意是新安装的mysql路径<br />
<em>mysql_config=/usr/local/mysql/bin/mysql_config</em><br />
编译、安装<br />
<em>python setup.py build<br />
python setup.py install</em><br />
声明libmysqlclient路径<br />
<em>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/mysql/lib</em></p>
<h2>3. 安装服务器环境</h2>
<h3>下载安装fastcgi头文件</h3>
<p><em>wget http://www.fastcgi.com/dist/fcgi.tar.gz</em><br />
解压，默认编译安装</p>
<h3>下载安装PCRE</h3>
<p><em>wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.00.tar.bz2</em><br />
解压，默认编译安装</p>
<h3>下载lighttpd</h3>
<p><em>wget http://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-1.4.25.tar.bz2</em><br />
configure时指定<em>&#8211;prefix=/usr/local/lighttpd</em><br />
编译，安装</p>
<h2>4. 配置</h2>
<p>lighttpd fastcgi运行web.py程序请参考<br />
<a href="http://www.classicning.com/blog/2009/11/lighttpd%e9%80%9a%e8%bf%87fastcgi%e8%bf%90%e8%a1%8cweb-py%e7%a8%8b%e5%ba%8f/">http://www.classicning.com/blog/2009/11/lighttpd%e9%80%9a%e8%bf%87fastcgi%e8%bf%90%e8%a1%8cweb-py%e7%a8%8b%e5%ba%8f/</a></p>
<p>非常重要的几点注意：</p>
<ul>
<li>通过fastcgi运行的python脚本必须具有可执行权限，<em> chmod u+x web/main.py</em>；</li>
<li>重启fastcgi程序需要删除/tmp/fastcgi.socket*</li>
</ul>
<p>任何Python程序出错、权限错误都会导致lighttpd这样的报错：<br />
<em>2009-11-27 18:12:02: (mod_fastcgi.c.1108) child exited with status 13 /home/admin/web/main.py<br />
2009-11-27 18:12:02: (mod_fastcgi.c.1111) If you&#8217;re trying to run your app as a FastCGI backend, make sure you&#8217;re using the FastCGI-enabled version.<br />
If this is PHP on Gentoo, add &#8216;fastcgi&#8217; to the USE flags.<br />
2009-11-27 18:12:02: (mod_fastcgi.c.1399) [ERROR]: spawning fcgi failed.<br />
2009-11-27 18:12:02: (server.c.931) Configuration of plugins failed. Going down.</em></p>
<p>报错会提示fastcgi未正确安装，而实际上仅仅是程序错误或权限问题而已。</p>
]]></content:encoded>
			<wfw:commentRss>http://sunng.info/blog/2009/11/%e5%9c%a8rhel4%e4%b8%8a%e6%90%ad%e5%bb%bapythonlighttpdfastcgi%e7%8e%af%e5%a2%83/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	<georss:point>31.203057 121.6174866</georss:point>	</item>
	</channel>
</rss>
