大家好,我是慕枫
前阿里巴巴高级工程师,InfoQ签约作者、阿里云专家博主,一直致力于用大白话讲解技术知识
在这里和大家分享一线互联网大厂面试经验、技术人成长路线以及Java技术、分布式、高并发、架构设计方面的经验总结
感恩遇见,希望我们都能成为更好的自己
创建了慕枫技术面试现场社区,主要分享大厂面试问题,欢迎大家加入,慕枫技术面试现场
在操作系统领域当中,死锁指的是两个或者两个以上的进程在运行的过程中,因为争夺共同的访问资源而相互等待阻塞,最终造成阻碍进程继续执行的一种阻塞现象。那么在数据库领域当中死锁又是怎样的表现形式呢?
如下图所示,假设事务A持有行1的共享锁,事务B持有行2的共享锁,那么此时事务A请求持有行2的排他锁,那么在事务B释放资源之前都处于阻塞等待的状态,同样的事务B请求持有行1的排他锁,在事务A 释放资源之前同样也是处于阻塞等待的状态。也就是说事务 B 完成之后事务 A 才能完成,而事务A的完成又依赖于事务B的完成,这就形成了循环依赖的问题,最终导致死锁情况的发生。
//先确定数据库有没有死锁情况发生
select * from pg_stat_activity where datname = 'product_db';
//查询可能锁了的表的oid
select oid from pg_class where relname='product';
//查询对应的pid
select pid from pg_locks where relation='oid' //上面查询出来的oid
//取消或者终止对应的进程
select pg_cancel_backend(pid);
select pg_terminate_backend(pid);
以上分析了PostgreSQL出现死锁后如何定位分析,那么接下来就需要总结分析分析下数据库出现死锁情况的原因以及一般的应对解决办法。
索引使用存在问题的话会导致死锁问题,假设在一个数据查询的事务当中,进行数据检索的时候没办法按照SQL中的where条件进行查询,因此导致了全表扫描,那么此时数据库表的行级锁会上升为表级锁。如果此时有多个未能按照where条件进行数据查询的事务存在,那么就容易导致数据库死锁问题。也就是说在数据库表数据量比较大的时候,对应进行数据查询的表没有建立索引或者说索引创建的不合理导致无法通过索引进行数据查询,只能通过全表索引,这样的场景下就容易产生死锁。
如何避免:
在进行数据查询的时候,对应的SQL语句不宜太过复杂,也就是说尽量避免多张表的关联查询。
当用户A 访问数据库表A时,此时对表A加了共享锁,然后又访问数据库表B。而此时另一个用户B 访问表B,对表B加了共享锁,然后试图访问表A。但是用户A由于用户B已经锁住表B,它必须等待用户B释放表B才能继续,同样用户B要等用户A释放表A才能继续,也就是说互相等待对方释放资源,从而导致了死锁的发生。
如何避免:
这种情况在实际项目中遇到的可能比较多,主要还是需要通过控制代码的执行逻辑,避免多表操作时同时锁住多个资源。
(1)如果平台中存在大事务,尽量将其拆分为小事务。因为大事务一般操作的数据库表或者数据都比较多,因此造成死锁或者阻塞的概率就会相对较大。
(2)为数据库表设计合理的索引,尽量避免数据查询时索引未覆盖或者索引失效的情况,因为全表扫描会会导致给表中的数据行上锁,大大增加了数据库产生死锁的概率。
(3)如果业务允许,我们可以尝试将隔离级别调低,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。
创作不易,如果各位同学觉得文章还不错的话,麻烦点赞+收藏+评论交流哦。老样子,文末和大家分享一首诗词。
望江南·超然台作
春未老,风细柳斜斜。试上超然台上望,半壕春水一城花。烟雨暗千家。
寒食后,酒醒却咨嗟。休对故人思故国,且将新火试新茶。诗酒趁年华。