spprogrammer 2016-03-22
由于系统建设,原两台服务器应用增加到了四台,导致死锁频频发生。在以往两台服务器的情况下,一般很少出现,也就没有关注。最近服务器新增导致死锁现象非常频繁。经过几周的测试分析,终于找到了解决方案。现将分析及解决方案附上:
1.DBA核查数据库各属性参数配置正常
2.查找网络资料,提示所有查询QUARTZ_TRIGGER等表的SQL语句末尾增加with ur,将quartz中源码进行调整,但调整后仍会出现死锁;
3.根据DBA提供的数据,发现我们每个任务都是同一个JOBNAME。加之网络资料提示需要将JOBNAME增加索引的指导,修改代码将每个任务设置不同的JOBNAME。一般情况下无死锁现象,一旦在任务执行期间启动应用,则由于抢占资源等各种原因,死锁造成几何倍增长;
4.再分析死锁SQL以及quartz机制,发现quartz框架中StdRowLockSemaphore类中SELECT * FROM QRTZ_LOCKS WHERE LOCK_NAME = 'TRIGGER_ACCESS' FOR UPDATE并没有对数据上锁,咨询生产运维部DBA,默认的隔离级别是游标读(CS),数据读出来后就释放锁了,需再SQL语句后指定with rs;这个事务隔离与其他数据库(如Oracle)设置不同,一般Oracle数据库试用for update就会形成行级锁,而DB2则不可以。
好了,现在基本定位了,DB2数据库如果没有使用with rs,则为游标锁,使用完毕就会释放。对于DB2的事务控制,请自行搜索或咨询DBA,鄙人也不是特别明白,不做过多解释。
所以最终的解决方案是:对quartz源代码关于StdRowLockSemaphore类的SELECT * FROM QRTZ_LOCKS WHERE LOCK_NAME = 'TRIGGER_ACCESS' FOR UPDATE增加WITH RS,重新打包quartz即可。
另外,请仔细搜索所有的StdRowLockSemaphore类,可能一个项目中存在各种版本的quartz包,需要清理成一个,以免类加载时加载的到了未修改的版本。
我们系统使用的是quartz1.8.5,原则上1.8版本左右的都没有问题,其他版本请自行分析测试。