php比java的开发效率高几乎成了大家的共识了。为什么php开发起来会比java快很多呢?频繁的服务重启是众多原因之一。php开发者们编辑完了 php代码,只要刷新一下浏览器,就可以看到运行的效果了,从来没有编译和重启apache的问题。尽管现在的IDE能够自动编译部署和打包应用程序,但 是还是没有php便捷。这一年来一直在使用jboss 4.2 做开发,jboss号称有很强的热部署能力,但是更新一个应用后还是要等上一两分钟的时间让jboss重新部署应用,而且这种热部署时间一长就会发生内存 耗尽的错误。如果是用tomcat+spring这种轻量级解决方案,重启一次十几秒钟,还可以接受,但是jboss+seam要一两分钟,而且吃掉百兆 内存,实在让人受不了。有的时候感觉一天之中没有在专心写多少代码,都是在等待jboss重启中度过。我现在对这种工作方式越来越不满,我想要更好性能的 开发机器,使用更轻量的框架,更轻量的服务器。现在使用的seam相对spring+hibernate+struts来说,还是重量的多,而jboss 也没有tomcat那样轻巧。如果能够不用等待就可以看到程序运行的效果,java在开发效率上会离php更近一步。
jboss的热部署,是指不重启jboss的情况下部署应用,比如ear, war等。虽然不重启jboss,但是还是要卸载和装载应用,还是慢。
如何热部署jboss应用呢?如果应用是用打包方式部署的,更新一下包的修改时间就可以了。如果是以目录的方式部署的,对于ear,更新一下META-INF/application.xml的修改时间,对于war,则更新WEB-INF/web.xml的修改时间。更新修改时间,最方便的就是用touch命令了,如果你用的是windows,没有touch命令,你可以装一个cygwin,或者用ant的touch任务来代替。
November 18th, 2008你喜欢写程序吗?
你喜欢写程序吗?我问过同行很多次,但是还没有碰到过哪个人干脆的回答:我喜欢。相反,说不喜欢的却有很多人。我有个大学同学说:我不喜欢计算机,不喜欢写程序,是爸妈让我来学计算机的。有的同行说:没办法,在大学学了这个专业,所以就做这一行了,其实我不喜欢写程序。我得到的最多的答案是:程序员工资高呀,我才不喜欢写程序,如果我有其他方式挣钱,我就不做程序员了。我知道我接触到的这些人是这个行业的极小部分,我期望剩下的那绝大部分中能有很多人会喜欢写程序,否则,我们这个国家的软件行业就永远没有出头之日。我们这个国家的程序员中不缺少梦想一夜暴富的投机者,也不缺少沽名钓誉的学术骗子,更不缺少为求生计混日子的人,但我们非常缺少充满激情热爱写程序的人。
不能选择自己的生活是可怜的,为了点钱把每天三分之一的时间用来做自己不喜欢做的是事是可悲的。如果你是个程序员,却并不能再程序代码中找到快乐,我劝你还是做些别的吧,你的人生不应该在这里。
而我要自豪的说,我热爱我的行业,我喜欢让指尖在键盘上跳动,让思维在代码间流动,让创造力在CPU的脉动中体现。
September 26th, 2008数据迁移经验
做关系型数据库数据迁移的时候,为了加快速度,要注意以下几点。
充分利用数据库的能力
关系型数据库被设计成善于做查找,比较,排序等操作。在大数据量的时候,重新写个程序去对数据做查找排序等,效率往往比不过数据库。所以在数据迁移的时 候,应该尽量将此类操作交给数据库来完成。另外数据库往往都有自己的一些工具,比如导入导出工具,如果你的迁移过程要做类似的工作,也应当交给数据库来完 成。假如你要取出数据库里的一些数据,将格式做些转换,再插入到另一个数据库。你可以写个程序读一条,转换一条,写一条,但是这样很慢,还不如把数据导出 成csv等文件,然后再对文本处理生成新的另一个数据库的导入文件,然后再用另一个数据库的导入工具导入。我曾经做过这样的工作,将数据从sql server 2000迁移到 mysql,要对数据做些简单的格式转换,前一种方案用时40分钟,而后一种只要一分钟。
减少IO操作
现代计算机的CPU,总线和内存的速度都远超过各种IO的速度,所以减少IO操作就可以大幅提升数据迁移时的速度。使用连接池重复使用连接,减少新建连接 的次数可以减少IO操作。使用缓存将可能会被多次查询的数据缓存起来,减少查询数据库次数,可以显著减少IO操作。将中间结果缓存到内存或临时表中,非常 有用。最近在工作中遇到的数据迁移,通过大量的应用内存缓存,成功的将数据迁移时间有原来的近一周缩短到一个小时。
注意索引
也许你在做数据迁移时的很多查询操作是平时用不到的,所以并没有适合于做迁移查询的索引,那么你一定要记得在迁移前加上它。同样,需要被插入数据的表的索引还是先删掉吧,迁移完后再加上。
经常维护数据
不完整的数据,在迁移过程中是最让人头痛的。平时经常清理数据中的垃圾,如果垃圾成山了,数据迁移将是恶梦。
在jboss下,如果包含ejb的jar,和要通过local接口访问ejb的war不被打包成一个ear来部署,会遇到问题。如果你的war中包含了ejb3的local接口的class,那么war在通过jndi取得ejb的引用试图将其转化成接口类型时会抛ClassCastException。而如果war中不包含local接口的class,则会抛class not found的异常。这都是由讨厌的classloader问题导致的。每个放到jboss的deploy目录里的部署单元都有自己的独立的classloader树,这两棵树在jvm的classloader里是平级的。如果war和ejb jar里都包含了某个ejb的local接口的class时,那么同一个类就分别存在于两棵classloader树中。通过jndi取得的引用的类型是ejb jar中的local接口的类型,将其转化成war里的那个local接口类型时就出错了,因为它们不是同一个类。而classloader是不能访问同级的其他的classloader下的类的,所以如果war里不包含接口的class,有会因找不到class而出错。
这种时候就是使用ear的时候,位于同一个ear里ejb jar的classloader是war的classloader的父classloader。这样,只需要部署一份接口类,war也能访问到它,因为子classloader能访问父classloader载入的类。
当你用jsf的<h:selectOneMenu />之类的控件选择实体时,小心你的实体的equals方法,否则你可能就会遇到”value is not valid”的验证错误。比如,如果你的页面里有这样一段:
<h:selectOneMenu value="#{fooAction.foo}">
<s:selectItems value="#{fooList.resultList}" var="foo" label="#{foo.name}"/>
<s:convertEntity />
</h:selectOneMenu>
你的Foo实体类的equals方法又是这样写的:
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Foo other = (Area) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
很好,你很可能就有机会遭遇seam下这个神奇的value is not valid验证问题了。到底原因何在?原因就在于seam不仅使用了jsf还使用了hibernate,而你的equals方法没有考虑到被对比的双方可 能一个是实体类,另一个可能是被hibernate动态增强过的类。JSF在客户端提交表单后,会验证客户端选中的元素是否是当初服务端给他的那些元素。 所以,JSF会拿经converter得到的实体与当初的集合里的实体一一调用equals方法对比,如果找不到一个在集合中的实体与提交来的一样,就报 错。如果集合里的对象是hibernate 延迟加载时的一个stub,那正常的对象和这个stub对比时就可能出错。对于上面的例子,getClass() != obj.getClass() 会为真,而 other.id != null 也可能为真。怎么办?改写equals方法,如下:
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!getClass().isAssignableFrom(obj.getClass()))
return false;
final Area other = (Area) obj;
if (id == null) {
if (other.getId() != null)
return false;
} else if (!id.equals(other.getId()))
return false;
return true;
}
isAssignableFrom方法对子类调用时一样为真。other.getId()时,则会初始化stub,取出id的值。
还有一种更简单的方法,那就是不要让用户选择实体,而是选择实体的id,那就没这个问题了。