懒惰是我们的天性
在这个项目里已经几天了,现在手头的任务是把现有的sql语句从代码里抽出来,开始同事们的做法是一行一行地从代码里copy,看着长达几十行的sql语句,我会那么勤勤恳恳地把每一行都copy出来吗?这么枯燥的工作可以让程序来完成,懒惰是程序员的天性!!! 写个工具来解析岂不是会很快?说到做到,一个简单的文件读取,一个基于正则表达式的解析器,解析结果输出到一个结果文件里,10分钟搞定!接下来,把这个工具推荐给同事们,结果本来计划2天的工作量一个上午搞定。
懒惰是我们的天性
在这个项目里已经几天了,现在手头的任务是把现有的sql语句从代码里抽出来,开始同事们的做法是一行一行地从代码里copy,看着长达几十行的sql语句,我会那么勤勤恳恳地把每一行都copy出来吗?这么枯燥的工作可以让程序来完成,懒惰是程序员的天性!!! 写个工具来解析岂不是会很快?说到做到,一个简单的文件读取,一个基于正则表达式的解析器,解析结果输出到一个结果文件里,10分钟搞定!接下来,把这个工具推荐给同事们,结果本来计划2天的工作量一个上午搞定。
又进了一个稍觉郁闷的项目
还没从上一个项目成功的喜悦走中出来,马上又被拉进另一项目了,昨天下午开始接触到这个项目的代码。看到现有代码时的心情只能用一个词来形容:terrible. 丝毫看不出这是一个用面向对象的语言编写的系统,无休止的if else,混乱的类层次结构,蹩脚的变量名,无休止的重复代码,长达百行的大函数,到处充斥着bad smell。。。。 想要做重构几乎没有可能,因为没有test case。
这是个部门以前做的一个项目,比较久远,现在需求变更了,需要对source做调整,然而这么苦难的事情就落在了我的头上。 “在写任何一行代码之前,先要考虑一下后来维护你的代码的人会不会被你的逻辑弄晕掉”我一定坚持这条规则。
罢!罢!罢!做什么不是给公司做,先尽力完成自己的任务吧。
解决了一个死锁问题
此问题中涉及到的对象有Subject
, Enclosure
, SubjectEnclosure
三个对象,
数据库中对应的三张表为 tbl-subject
, tbl-enclosure
, tbl-subject-enclosure
。
Subject和enclosure为一对多关系,在Subject中有个Set<SubjectEnclosure >
属性,用于保存隶属于该subject的附件,
SubjectEnclosure
中有个Subject
类型的属性(many to one),
Enclosure
类型的属性(one to one)此外还有一些其他属性(这也是为什么要做这个中间对象的原因)
在对一个Subject 类型的对象做更新时,如果连续多次更新,偶尔会出现server没有响应的情况,只有把tomcat重启才能恢复正常。
能够导致服务阻塞,重复操作才能偶尔出现,并且把tomcat重启后就能恢复正常,会不会是数据库发生了死锁?用下面的脚本一跑,出现如下结果:
查看死锁的脚本:
SELECT substr(v$lock.sid,1,4) "SID",
substr(username,1,12) "UserName",
substr(object-name,1,25) "ObjectName",
v$lock.type "LockType",
decode(rtrim(substr(lmode,1,4)),
'2','Row-S (SS)','3','Row-X (SX)',
'4','Share', '5','S/Row-X (SSX)',
'6','Exclusive', 'Other' ) "LockMode",
substr(v$session.program,1,25) "ProgramName"
FROM V$LOCK,SYS.DBA-OBJECTS,V$SESSION
WHERE (OBJECT-ID = v$lock.id1
AND v$lock.sid = v$session.sid
AND username IS NOT NULL
AND username NOT IN ('SYS','SYSTEM')
AND SERIAL# != 1);
结果:
table lockType lockMode
tbl-subject TM ROW-X(SX)行级排他锁,提交前不允许做DML操作
tbl-enclosure TM ROW-X(SX)
tbl-subject-enclosure TM ROW-X(SX)
再查看一下更新subject时执行的sql语句。
update tbl-subject set ......
update tbl-subject-enclosure set ...
update tbl-enclosure set ...
update tbl-subject-enclosure set ...
update tbl-enclosure set ...
-------------------如果发生死锁,下面的sql就无法执行----------------------------
update tbl-subject-enclosure set ...
因为是 tbl-subject-enclosure这个表被锁住了. 仔细分析sql语句, tbl-enclosure只有在插入subject时需要被插入数据库, 后面对subject的更新操作只需要维护tbl-subject-enclosure这个中间表就可以了, 无需对tbl-enclosure做更新操作,更改SubjectEnclosure中Enclosure类型属性(one to one)的级联type(原来是ALL,改为MERAGE), 再更新Subject,发现此时已经不更新enclosure表了,死锁不再出现了!
Spring, Hibernate, Struts2项目总结
今天做完了第一个正式的公司内部的Spring Hibernate Struts2项目,这个项目与我进入公司后的任何一个项目都不相同,有了很大的收获,值得总结一下。
项目时间:3.5 week
项目人员:
这个项目采用的是比较新的技术,因此在构建项目框架,编码过程中,遇到了不少困难,主要集中在以下几个方面:
1,没有很好的OO意识,面向过程编程
2,不愿意重构代码,影响可读性,可测性
3,对持久化框没有大致的了解,对数据持久化的认识仍然停留在 关系数据库的层面上。
4,公共模块变化较多,而且不能及时反应给其他模块开发着。
5,只关注功能实现,忽略了性能调试。
1,在开始编码之前,详细地分析业务需求,然后从需求中抽象出业务对象,充分利用 设计模式 来设计自 己的对象以获得更好的可读性和扩展性。
2, 编码过程中及时地重构自己的代码,提取公用函数,抽取对象,尽量把每个函数的行数控制在十几行的范围内,遵循函数功能单一化的原则。
3,理解Hibernate的原理,采用面向对象的观点去理解数据库。
4,及时地和开发人员沟通,共通模块的性能是整个系统性能提升的关键。
5,尽可能减少代码里的bad smell,用最少的代码做最多的事情,尽量少用循环。
当然,由于我负责这个系统框架的构建,所以学到的东西也很多。 1,系统采用贫血模型,把对象的行为(service)和状态(pojo)分离,系统结构如下:
3,如果你要问我第一次使用TDD方式开发会不会很困难,还是比较容易的,因为我做的主要是公共模块,那些模块比action要好测试些。
4,Hibernate 通过一个玩具项目,一个正式项目,我对Hibernate的认知有了一定的积累,特别是在性能优化方面,有了不少收获。现在总结如下:
5,struts2 与struts1相比,struts2让人眼前一亮,更少的侵入性 保证了struts2的action更加容易测试。
关于strut2中的TypeConverter 和 validation 在上一篇文章中已经提及,这里我想再说说struts2的拦截器。拦截器是struts2的精髓,struts2自带的拦截器(在struts-default.xml中)就可以完成大多数的web开发需求,有空我会把struts-default.xml中的拦截器做个介绍。 在使用struts2的过程发现一个action中的函数有被执行两次的情形,原因是使用了struts2标签 的同时调用了 onclick()函数,在这里给大家提个醒,别再在这上面浪费时间:-)
最后还有个大难题: 我们的这个系统使用了c3p0数据库连接池,在系统运行一段时间以后,会出现tomcat假死的情形,具体现象为 页面一直在加载,一直加载不好。我又不知道怎么看tomcat的线程情况,留个脚印,寻找方法中。
Update: 问题解决了,是更新数据库时发生了死锁,解决方法看这里
开博啦
今天看到一个程序员用博客记录了他从开始工作到现在的点点滴滴,很受震动,算算现在也工作一年, 也学到了很多,接触到了很多东西,但是从来没有去认真地总结一下,下定决心,从今天起,留下自己在生活中的足迹