背景:
最近在折腾换OA系统,遇到了一个很诡异的事情。在测试阶段,OA系统经常莫名地宕机,停止响应。查下来,发现是数据库出现大量死锁,耗尽了连接池。出现问题的语句是一样的,问题锁定在QRTZ_TRIGGERS表更新上。
(@P0 nvarchar(4000),@P1 nvarchar(4000),@P2 nvarchar(4000),@P3 nvarchar(4000))UPDATE QRTZ_TRIGGERS SET TRIGGER_STATE = @P0 WHERE SCHED_NAME = 'clusteredScheduler' AND JOB_NAME = @P1 AND JOB_GROUP = @P2 AND TRIGGER_STATE = @P3
潜在的解决方案一
在网上找到一篇文章:
Deadlocks in Qrtz_Triggers table
按他的建议处理后,死锁现象没有了,但是服务器仍然不稳定
OA厂商建议修改jdbc url 配置参数将 SelectMethod=cursor 变更为 SelectMethod=default
潜在的解决方案二
找到另一篇比较旧的文章 Deadlock on QRTZ_TRIGGERS / QRTZ_JOB_DETAILS with MS SQL Server + Intermediate Timer
给出的解决方案是:
1.SQL SERVER DB设置为启用READ_COMMITTED_SNAPSHOT
ALTER DATABASE <DBNAME> SET ALLOW_SNAPSHOT_ISOLATION ON
ALTER DATABASE <DBNAME> SET READ_COMMITTED_SNAPSHOT ON
- 修改quartz-definition.properties配置文件
org.quartz.jobStore.acquireTriggersWithinLock=true
关于quartz-definition.properties配置文件:
在quartz库的jar文件里能找到它
参见文章 quartz.properties配置文件详解。
官方文章Quartz Configuration Reference
关于READ_COMMITTED_SNAPSHOT:
READ_COMMITTED_SNAPSHOT设置的是“隔离级别”。sqlserver默认隔离级别是已提交读,但是它的已提交读定义和别的数据库其实是不一样的,写会阻塞读,一定条件下读也会阻塞写,非常影响高并发系统性能。通常,我们需要在创建数据库时设置允许快照读,或者沟通业务停机时间进行设置。参见文章sqlserver 修改数据库隔离级别
关于隔离级别的官方说明
查询隔离级别设置
select is_read_committed_snapshot_on,*from sys.databases where name= 'test'
公司用的是阿里云RDS,SET ALLOW_SNAPSHOT_ISOLATION ON时没有障碍,但是在SET READ_COMMITTED_SNAPSHOT ON时遇到问题,提示错误“Some operations are not allowed on a database that is participating in a database mirroring session or in an availability group.”。解决方案参照上面的文章参 sqlserver修改数据库隔离级别,要点是先将DB改成单用户独占模式,然后再改,改好后再恢复成多用户模式。
对于阿里RDS, “alter database db_ptype set partner off;”这句非常重要!!
alter database db_ptype set partner off;
ALTER DATABASE db_ptype SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE db_ptype SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE db_ptype SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE db_ptype SET MULTI_USER;
但是在改成单用户模式时,如文章SQL SERVER单用户模式描述,是很容易出现冲突的。解决办法是查出有哪些进程,然后强行kill. 用到的命令:
sp_who
SQLServer 2012 数据库脱机与联机操作
KILL