项目初期上线,经常会出现查询超过10分钟、程序无响应、操作报错死锁牺牲品错误,这些都与死锁有关
原因分析
1、查询超过10分钟
大量的报表查询,平均查询时间超过3秒以上,并且关联了很多张表,其中包括关键业务表和百万、千万级的表,而查询与更新同时发生,便会有几率发生死锁(原理请参考这篇文章),查询的时间越长、更新操作越频繁,几率越大
2、上了消息推送功能,频繁出现大面积用户程序无响应,白屏
新功能引起了多用户并发查询,而这些查询都与关键业务表关联,出现了场景1的表锁问题,锁住了用户、权限表,而我们每一次请求都必须要先查这2张表,这就阻塞住了所有请求,异步请求会一直处于loading状态,异步请求便会引起程序无响应
3、流水号获取频繁死锁,每天要发生5次左右
有几类单据新增时都会获取一个唯一的自增长流水号,流水号的获取是先查询,然后+1再更新,如果2个请求同时发生,会出现2个事务同时查询,同时上了S锁,当这2个事务要更新的时候得不到X锁,便出现了死锁
总结:
从宏观的角度上看,死锁的发生场景主要有2类,一是查询和更新并发,二是2组更新并发
而死锁本身不是错误,他只是数据库的一种机制,为了保证数据的一致性
对于第一种场景,大量的慢查询都是用于列表的展示,实时性要求并不高,我们不需要数据库帮我们保证数据的一致性,我采取的方案就是把不需要数据一致性的查询加上nolock
对于第二种场景,我们需要保证数据高度的一致性,例如在生成流水号的过程中,其实是不应该允许其他事务读的,我的做法是,读的时候就强制加X锁(WITH(XLOCK))