Archive for 2011

JDBC的批量更新测试

上回书说道MySQL的auto-reconnect的问题,可以通过重新建立Connection的方法解决之,于是我就更新了一下该数据库封装类。这里介绍一下背景:为了使用方便,一些小型项目中,我倾向于直接使用JDBC,这样执行效率和开发效率相对而言都比较高,而实际使用中,所有的数据库操作,都被封装在一个DatabaseFactory类中(有时间我会考虑一下,整理一下Open Source It)。

在修改这个类的过程中,顺便研究了下数据批量更新的效率问题,分析结果如下。由于对于不同的数据库,效果也不尽相同,这里以MySQL和Oracle为例,并分开描述:

MySQL:

MySQL本身并不支持批量更新,只是驱动程序提供了这个特性,只有高版本才支持该特性,并且连接URL上必须加上

rewriteBatchedStatements=true

这样的参数,这样驱动程序会自动将多条SQL语句拼接成一条,从而提高了执行效率。

...
for (int i = 0; i < sqlList.size(); i++) {
stmt.addBatch(sqlList.get(i));
}

stmt.executeBatch();
connection.commit();

效率提升是必然的,原因很简单:非批量更新方式,autoCommit=true,每一条SQL语句都会自动提交,都会产生网络数据包、磁盘IO。而批量更新方式,只会产生少量的数据包,因为很多条SQL语句被打成一个数据包,一次性的通过网络传输到服务器,相应的,服务器的IO操作也少了很多,当然效率自然会提高。

就是因为这个和网路相关,所以网络环境不同,产生的提升效果也不相同,经测试,在比较快速的网络环境下,比如局域网,我的试验结果是:10万条SQL语句,在非批量情况下,使用了约36秒,而批量操作只使用了约9秒,效率提高了3倍。

如果在比较差的网络环境下,提升的效果会更明显,我使用VPN从家里连接到公司的内网,更新1万条数据,非批量方式,大概需要270秒左右,而批量方式大约9秒,提升了近30倍。效率提升的倍数和很多因素相关,比如刚才提到的网络环境,每次提交多少条SQL语句也很关键,并且MySQL表的类型也会影响这个:MyISAM类型的表的提升效率就远远的高于InnoDB类型的表。

注:上述的所有的所有测试都没有使用Prepared Statement,只是使用普通的Statement和executeBatch(),如果使用Prepared Statement,几乎没有任何效率提升,后来发现是因为我用的mysql-connector-java的版本过低(5.1.8),替换为5.1.17后,VPN状态,效率提升50倍左右。

Oracle:

和MySQL相反,Oracle使用批量更新,如果不使用Prepared Statement,效果可能会更差,使用了Prepared Statement,我用VPN连接到公司的内网,效率提高了75倍左右。可能是因为我用的Oracle JDBC驱动对非Prepared Statement的支持不够好吧。

MSSQL:

待测试,稍后更新…

小结

数据库更新的效率提升,由很多原因决定:网络环境,服务器内存、服务器I/O、驱动版本、代码编写方式、数据库的版本、表的类型等。我们必须综合考量所有因素,才能达到理想的效果。推荐你在你实际的环境中做相应的测试,找出最优的方法,别人的优化方法,不一定完全适用于你,比如这里提到的提升倍数,每个人的试验结果肯定不一样。

MySQL的Connection自动断开问题

MySQL缺省配置下,会自动断开那些idle超过8小时的Connection,如果应用程序保持这个连接,8个小时(wait_timeout=28800秒)后,用JDBC,再次访问数据库,会有异常抛出,据说用autoReconnect=true可以避免这个问题,不管你信不信,反正我信了,而且好多年前,我就这么做的。

直到最近,在一个鲜有人访问的应用中发现,问题依旧,8小时候后的第一次访问,总是失败,刷新一下页面,就正常了。Google了一下,才知道MySQL不推荐使用autoReconnect=true来解决此问题,http://bugs.mysql.com/bug.php?id=5020,如下:

[12 Aug 2004 18:46] Mark Matthews
Note: Autoreconnect functionality will be depcreated and eventually removed in future
releases. 

The reason this isn't working for your particular case is that the methodolgy for
autoreconnect was changed to be safer after 3.0.11, and is related to autoCommit state,
which will also cause the current 'in-flight' transaction to fail (if you attempt your
transaction again _after_ the failure, the driver will reconnect). Please see the docs
for the explanation on how to correctly use this feature in the 'Troubleshooting'
section.

In any case, there is no 100% safe way that a JDBC driver can re-connect automatically if
a TCP/IP connection dies without risking corruption of the database 'state' (even _with_
transactional semantics), which is why this feature will eventually be removed.

The JDBC spec does not specify that a connection is alive no matter what happens to the
underlying network for this very reason. 

Clients of JDBC drivers are responsible for dealing with network failures, as only the
application itself (really the developer of the application) 'knows' what the 'correct'
response to a transaction failing due to the network going down is. 'Wait_timeout'
expiring on the server is basically a 'forced' network failure by the server. You can
correct this in a non-robust way by setting 'wait_timeout' higher, however, you as a
developer should be handling SQL exceptions in your code and taking appropriate recovery
actions, not just passing them up the call stack.

解决也很简单,记录最近一次的Connection访问时间,如果超过了8小时,就重新建立这个连接,经验证是可行的。另外也可以在建立Connection的同时,创建一个线程定时的去执行一个SELECT 1语句,前面的方法比较简单。

这里要指出的是,用Connection的isValid()方法去检测Connection是否有效是不行的,程序会死在那里(未调查原因),试图用isClosed()去判断Connection是否断开也是行不通的,因为只有明确的调用了Connection的close()方法后,你才能用isClosed()去判断,也就是说Connection在idle超过8小时候后,这个时候你如果去打印它的isClosed()的值,它还是显示false,但实际上却不能使用。

iPhone流量偷跑探秘

换了部iPhone,用的是联通的3G卡,96的套餐,一个月才340M数据,如果要每月1G以上的流量,就得办386的套餐,有些不划算,并且我的移动卡还继续用,算起来就更不划算了。于是先用起来再说。

前3个月,联通每月额外赠送500M的流量,三个月后就恢复到正常的340M每月,所以我得在前几个月把自己的使用方式和习惯建立起来,以便达到套餐使用的最大利用率。第一件事情就是分析自己的每日数据使用量。

于是乎,安装了几个流量监控软件,比如QQ手机管家,Data Usage等。几天监控下来,发现日平均流量很大,至少有几十兆,这样一个月下来,肯定远远超过340M的上限。这些流量监控软件都无法具体看到是哪个程序耗费了流量,所以很难对症下药。我猜测大概是邮件占了绝大多数流量,我设置了2个邮箱,一个Google Apps Gmail,一个是公司的Exchange,还有一个MobleMe的Find My iPhone,都是Push的方式。Push虽然很方便,但是对于这个套餐,太让人纠结了,只能关闭了。

关闭Push后,只开一个Data Usage软件,每隔10多秒观察一下,发现还有流量产生,小的几十、几百B,大的20、30KB。这个就让人纳闷了,难怪网上很多关于iPhone流量偷跑的帖子。Google了一下,发现一个Paros的软件可以嗅探到HTTP访问(我没有去找更好的软件,比如Sniffer Pro,基于HTTP的分析就可以大概了解情况了)。用Paros设置好代理,将iPhone的Cellular Data和3G都关闭,只是使用Wifi,将代理指向Paros。结果很有意思:

需要上网的软件,使用网络无可厚非。那些看似无需网络的软件,很多也会偷偷的访问网络。举几个例子:

注:这些程序并非只访问一个地址,很多程序会访问很多地址,很多次,我只是列出了一个而已。

很多游戏需要连接到Apple的Game Center,即使是非网络游戏,启动的时候也要联网。让人受不了的是,那个我用来检测流量的软件Data Usage也在不停的消耗流量,它每隔一段时间会从去访问一下它的服务器上的Version.txt,估计是为了提示更新。

我还发现有的软件,每次打开都去访问一下新浪博客的注册页面,URL后面跟着它的邀请码,不知道这样会不会给它带来收益,没有仔细的分析,不做论断。综上所述,结论如下:

  1. iPhone自带的单机软件,也可能访问网络
  2. 第三方的单机软件,更是扑朔迷离,有的为了广告,有的为了了解自己软件的使用情况,有的为了别的目的
  3. 单机版的游戏可能会在和Game Center通信的时候消耗流量
  4. 有的软件,没有做好优化,访问时,发送大量的数据,比如,下图中的‘我查查’,每次请求一个非常长的请求,浪费了用户的流量。
  5. 最后,如果你的套餐流量有限,不用时就关闭Cellular Data,否则联通就笑开了花。

 

下图为‘我查查’的请求URL之一:

上面的分析,不一定全面和准确,请自行验证,并且这里只有HTTP的嗅探,如果程序用别的方式访问网络(比如QQ),还是会消耗你的流量。但是管中窥豹,其他协议也不用具体分析了,分析了也不好解决。总之一句话:在天朝用3G,就得认这个蛋疼的命,如果资费便宜了,谁会在乎这点流量。

Flex项目的Session验证

[暂定用此方法]
一新项目,考虑到Flex做UI太方便了,准备用Flex做,遇到一个用户鉴权的问题。Flex本身是属于客户端的东西,无法获得Session,所以不能直接得知当前用户是否Session过期。

这里提到的解决方法是:写一个Filter,然后在doFilter()中,查看Session是否存在,如果不存在,就转向登录页面,比如SignIn.html。

看似简单,不过今天走了些弯路,我原先的web.xml配置如下:

<filter>
    <filter-name>authFilter</filter-name>
    <filter-class>org.charry.lib.rbac.filter.AuthFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>authFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Filter中转向到SignIn.html,这样有个问题:上面的配置会让所有的资源访问都会被转向SignIn.html,甚至对Sigin.html本身的访问都会被转向SignIn.html,造成无限循环,浏览器会指出该错误。所以我在doFilter()里面判断当前访问的资源的URI是否包含SignIn.html,如果包含,就不做redirect。不过,这样还是有问题,SignIn.html页面里面会引用一些其他的资源,比如foo.js, bar.swf, foobar.gif等,对这些资源的访问也会被redirect。所以我尝试将Filter配置如下,也就是说只过滤html页面:

<filter>
    <filter-name>authFilter</filter-name>
    <filter-class>org.charry.lib.rbac.filter.AuthFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>authFilter</filter-name>
    <url-pattern>*.html</url-pattern>
</filter-mapping>

这样还是会有问题:因为SWF文件可以访问,很多Flex项目的SWF文件是可以直接使用的,所以,还存在用户鉴权的问题。由于该项目用的是BlazeDS,我只要堵住所有的DataService的Servlet就可以了,所以我最后用了如下的配置:

<filter>
    <filter-name>authFilter</filter-name>
    <filter-class>org.charry.lib.rbac.filter.AuthFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>authFilter</filter-name>
    <url-pattern>/messagebroker/*</url-pattern>
    <url-pattern>*.html</url-pattern>
</filter-mapping>

第一个模式匹配的目的是:让所有的AMF调用全部用过滤器检查一下权限,第二条的作用是所有的.html也要经过过滤器检查(此条不加,会出现刷新未登录页面,不跳转的问题)。新的问题又来了,我原先的Session管理是用BlazeDS调用的,现在自己把路堵死了,所以只能再写个单独的Servlet用来实现用户登录,完整的Filter和Servlet配置如下:

<filter>
    <filter-name>authFilter</filter-name>
    <filter-class>org.charry.lib.rbac.filter.AuthFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>authFilter</filter-name>
    <url-pattern>/messagebroker/*</url-pattern>
    <url-pattern>*.html</url-pattern>
</filter-mapping>
<servlet>
    <servlet-name>loginServlet</servlet-name>
    <servlet-class>org.charry.lib.rbac.servlet.ServletLogin</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>loginServlet</servlet-name>
    <url-pattern>/loginServlet</url-pattern>
</servlet-mapping>
经验证,方法可行,但总觉得比较麻烦,继续留意是否有更为简便的方法。

关于培训

又是在职场节目中看到的,很多人把在职培训看的很重要,觉得将来可能从中能学到很多东西。对此,我持保留意见,在我看来,在职培训是个有也罢,无也罢的东西。原因有三:
其一:时间短,培训时间通常只有几天或几周不等,有的会长些,这么短的时间不能系统化的学习
其二:培训师水平不济。关于培训师,一种是企业从外面聘请的专人,一类是内训师,通常内训师的存在是为了节约成本。我们姑且认为外面的和尚会念经,而内训师很多都是兼职,难免有赶鸭子上架之嫌,多数情况对培训项目无法完美的掌控(内容的熟练程度、学习气氛的调动、进度安排等)
其三:培训的内容多数流于表面和理论,很多都是多数人都知道的东西,只是在培训期间显得有些系统化

我所推荐的培训方式是:
一:自学,具体的途径有很多种,阅读相关书籍,在线资料,论坛交流等。优点是,你可以按照自己的需要,灵活的调配时间,以及你要学习的深度和范围;缺点是,有了问题,没有培训老师给你解惑,但是网络上热心人士如此之多,这个不是个大问题。
二:On Job Training,中文不好翻译,叫‘在职培训’?似乎不对,大概是实战训练的意思,这个会给我们带来第一手的信息。对于知识,听来的,和自己切身感受到的是完全不同的,就犹如你买个地球仪,不能当做环游世界一样。对于此法,如果有些企业做job rotation(工作轮换),比较合适。

Trip to Canada

第一次到加拿大,第一印象是:这里天黑的真晚,出了Toronto机场,都已经晚上9点左右,天还是亮的。第二印象是:这里的天空真的很蓝,很清澈,可以看的很远,所见之处都是色彩很鲜艳。我和同事说:The sky is very clear in Canada,他回到:The sky is clear everywhere, except for China。虽然是开玩笑,但是却大约是事实。

下面是透过玻璃拍的,还是蛮清楚的:

Niagara Falls所在的小镇和 Lake Ontario

奇怪的WinSCP登录问题

Linux下的/etc/motd的作用是全局的消息提示,我想为每个账户设置自己的motd,就在$HOME/.bashrc的最后加了行:

~/.msg

而.msg的内容如下:

#!/bin/sh

. /mnt/autofs/dvlp/libs/shell/color-def.sh
def_colors

echo Welcome to"$c_red" viper project"$c_normal" home directory:

echo 1. "$c_blue"vupload-install"$c_normal" – upload install.bin to OSAT home dir
echo 2. "$c_blue"vinstall"$c_normal" – install viper to OSAT
echo 3. "$c_blue"vget"$c_normal" – get files from OSAT to local
echo 4. "$c_blue"vput"$c_normal" – put files from local to OSAT

这时候用WinSCP登录,就会遇到一个奇怪的问题,它一直提示:The error is typically caused by message printed from startup…这样的错误,无法登录。Google了一下,无解。大概是因为WinSCP不支持在.bashrc里面打印出字符。

解决方法:将~/.msg 移至 .bash_profile 即可。

求职技巧漫谈

文:Charry

最近在Youku上看了几期《非你莫属》和《职来职往》,再加上也面试过一下新人,写写我的感受。

如何成功求职,是一个老生常谈的问题,Google一下,很多文章都在谈这个。希望下面这些内容可以作为一些初入职场的新人的参考:

简历

好的简历是通向面试的敲门砖,纵使你再有才,如果没有适当的表现出来,也将淹没于茫茫人海之中,所以第一步,你得好好准备一下最近的简历。简历的质量取决于内容,而非材质、包装,如果你不是艺术类专业的应聘者(也许艺术类的也不需要这样),无须将简历做得和个人专辑一样,反而会让人觉得你只重外表,不重内涵。好在现在很多招聘网站都提供简历模板,通常比你自己做的专业,企业HR部门也会直接将它们打印出来,各方都省事了。

除了姓名、联系方式等必要信息外,简历上要写明自己的过往职业记录,这里不要像流水帐一样记录每一个细节:要突出“重点”,所谓的重点是你在该阶段是什么角色,做了什么主要项目,以及你是如何贡献自己的力量的。注意这些黑体字,这些都是突出你自己的地方,你需要在这里让别人能看出你的特质,企业所需要的特质,技术上的或者软实力上的。所以要着重强调你的加分点,而不是罗列你的过去。而且,企业的管理层都比较忙,很多人,很可能都没有认真看你的简历,就匆匆的去面试你了,坐在你面前才开始翻看两下。这个是事实,只是很多面试官或者企业不愿意承认而已。你觉得在这种情况下,你洋洋洒洒几百字,几千字,让这些面试官肿么看啊,时间这么短?万一你的一个闪光点就这么被忽视了,怎么办?

内容得体,成熟稳重。不要为了突出自己的所谓的特点而过度的强调它,比如我前两天面试了一位,他的简历上用红色标注:“英语流利,标准的美国口音,有着西方式的思维方式”,而且中英文简历都是加强注明了这一点。英语流利算是你的强项吧,有着西方式的思维,这个不算好也不算坏,中西各有所长,我实在是不明白,他把‘标准的美国口音’放在简历上并着重强调,需要传达一个什么样的信息。美国口音并不比印度口音高尚多少,除了容易懂些。

要有所权衡,有人应聘软件开发职位,他简历上还写了精通Word、Excel、Window操作、HTML语言,有这个必要吗?对此我们可以这样解读:如果你真的很有技术能力,且也精通Word、Excel等,那么你不懂如何分辨优先级(prioritize),也不擅长决策(decision making)。另外一种可能是:你真的只是精通那些技术了。

形象

如果你只是面试一个技术职位,并且不是管理层,Senior及以下,可以跳过。如果目标公司是一个Geek型的公司,也可以跳过,他们可能不太注重形象。否则,你得稍微注意一下自己的着装、言行等形象。

为什么,因为企业招聘这类人,通常是期望你去带领一个团队,即使不是现在,也是想让你以后去带领一个团队,你需要有一定的‘范’。这里的‘范’包括:穿着稍微正式一些,西装革履太正式了,并非一定需要,但总不能穿着运动服就去了。言语上需要得体,不要满口口头禅,或者说些不适合在公开场合说的话语。举止要得体,不要看起来畏畏缩缩的样子,将来如何带人?

试想你每天的要面对的老板,头发如雀巢,穿着运动服,看起来畏畏缩缩,你心里恨不得上去揍他一顿,你会信服于他吗?

这里要说的不是让你只是在面试的时候注意,而成功后就我行我素。我的意思是:如果你有你的职业规划,得尝试着有所改变,上面说的几点就是。

准备

准备下一些基本的问题,比如你跳槽的原因、为什么有空档期、对目标公司的认识、你所理解的应聘职位是什么样的,等。别在面试的时候说的前言不搭后语,也许这些问题让那些面试官自己来回答也是回答的稀里糊涂(如果不准备的话),这也是事实,但是通常人们就是期望应聘者在面试的时候表现的比平时好些,总是有意无意的拉高标准,退一步想,面试是什么时候,你连这个时候都不重视,将来你还会对什么重视呢?

专业性问题,一定要先温习一下,现在是信息发达的时代,很多东西,你无须个个都记住,重要的思维方式等,而非好记性,Google就可以了,一个你平时可以稍微多花一丁点时间就可以做的很完美的问题,但是面试的时候,你如果回答不上来,从面试官的角度看来,你就是不懂。

非专业性问题,比如谈谈你对某些项目管理中遇到的问题的看法,通常这些都是开放性的问题,一定回答的有所重点,不要说了半天,让人无法理解你的意思是什么。是就是,不是就不是。

沟通

一定要有诚意,没有诚意,装总会吧?(有人说面试就是两个人面对面坐着,互相欺骗)但是不推荐。比如,有面试者被问到为什么想跳槽,有什么原因使其有离开当前公司的打算,他答道:也不是说一定要走,只是来看看,有好的就跳,没有好的就带着。拜托,大家都很忙,你是来参加《职来职往》的吧,有木有?面试官也伤不起的啊。

再者,大多公司有人员流失率(turnover rate)的KPI,你如此回答,会让人觉得你不够忠诚,将来难免会走。让你进来,万一走了,浪费时间、精力,影响项目进度、影响士气,KPI都被拖后腿了。这样的人通常会被忽视。

不要一味诋毁上一次公司,这里不好,那里也不好,没有感恩的心态,如何做人。有些人总是爱指责别人,自己总是对的,别人总是错的。这种人没有团队合作精神(teamwork),将来势必影响成员之间的合作,会把整个team搞的鸡飞狗跳,组织杀伤力很强。

职位

记得要问清楚你应聘职位的信息,是不是你所期望的,如果你误解了那个职位,然后进去了,那就杯具了,浪费大家时间。有些公司的职位描述(JD)没有专门人把关,HR也不了解具体部门细节,业务部门就随便找个人写了,他写的是他理解的,并非是完整的、合适的,HR也不清楚,就发布出去了。

所以企业发布的广告不一定是精准的,有些甚至是人为模糊之。你一定要问清楚了,充分核实。

薪资

一般人跳槽前,通常会把自己的当前薪水多写一些,然后再加一些就是期望薪水。如果水分太大,反而可能导致面试机会的丧失。要知道,HR们通常手里有一份本地区的同类型企业的,不同层次,不同职位人的平均薪资表。可能是互相交流得来的,也可能是从第三方专业机构买来的。如果你在原公司是个Engineer,你说你拿了个Section Manager的薪水,HR估计直接就把你过滤掉了:不诚实,期望太高,可能不稳定。

应聘者,尤其是新人,在我看来不必过分的看重薪资。学习,打好基础最重要,你踏踏实实的做好了,老板自然会给你加的,还怕你走了呢。

猎头

让猎头帮你找工作,可以说是一种不错的方法,这个只对于中高级人才有效,猎头公司一般不会接5年以下或者当前职位比较低的求职者的简历的,他们需要拿提成,那条线以下没甜头让他们赚。如果你符合条件,可以多找几家猎头公司,把简历提交给他们,让他们给你物色职位。

猎头公司也会告诉你一些目标公司的基本情况,公司看中的特质,这些只能作为参考,有的公司的招聘部门的JD都写的很泛,或者只有业内人士才能看的懂,猎头拿到的JD可能不准确的,或者被误读了。所以猎头的建议也只能作为参考,不可尽信。

广告

企业可以做广告,你也可以。微博让每个人成为了新闻中心,同样,你得善于运用一些求职类网站,比如,智联招聘、中华英才等,HR常光顾那里,或者一些职业SNS,比如LinkedIn,这是猎头常出没的地方。

其他

要准时。(我想到了再补),如有帮助,欢迎来信分享你的喜讯。

祈祷与祝福

生命失去了,再知道可贵,时光错过了再知道后悔,近日,媒体中充斥着日本灾难的新闻,恐慌的气氛已经传播到中国,今天的抢盐就是例证。发帖一枚,希望各位,珍惜自己,珍惜自己和家人朋友或者佳人朋友的相处的时光。在灾难面前共携手,在困难之时不低头。

祝福每一个你、我和TA,Life is short, play more(人生苦短须尽欢),该恋爱的恋爱,该结婚的结婚,God Bless JP, God Bless Everyone.

Using Putty on Windows to login Linux securely via OpenSSH

有些日子没更新了,随便发个凑个数。

我一直用的是PuTTY Connection Manager,它的自动登录的功能不错,好虽好,也有些不尽如人意的地方,还是直接用PuTTY方便,遂配置了基于Key的登录方式,具体方法请参考这篇文章:http://linux-sxs.org/networking/openssh.putty.html

如何配置,链接中的文章说的很清楚了,有一点需要强调的是:配置文件的权限必须设置正确,否则会报:Server refused our key 这个错误。只需修改权限如下即可:

$chmod 600 authorized_keys
$chmod 700 .ssh

完。

[ad]

Switch to our mobile site