今天收到《Test-Driven Development》书了。

上周在当当上订的《测试驱动开发》影印版,这周一就收到了,速度啊。前阵子在项目里试着做了点TDD,现在再拿这本获得Software Development Productivity大奖的TDD入门经典把知识再巩固一下子,在后面的学习过程中的心得也会逐一写到这里。

c3p0的helper线程数目过多导致内存溢出

前阵子做得那个系统发布了,结果刚放到服务器上就出了 outOfMemery 错误。 查看发现是由于下的进程导致的:

Daemon Thread [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0] (Running)

经过查找,发现在datasource里把c3p0的numHelperThreads设成了1000。正是由于这个线程过多导致了内存溢出,改成10就没有问题了。附上c3p0里对于 numHelperThreads的描述:

numHelperThreads Default: 3 c3p0 is very asynchronous. Slow JDBC operations are generally performed by helper threads that don’t hold contended locks. Spreading these operations over multiple threads can significantly improve performance by allowing multiple operations to be performed simultaneously.

懒惰是我们的天性

在这个项目里已经几天了,现在手头的任务是把现有的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表了,死锁不再出现了!