问题描述
度假后台在更新完DB的数据后会通知dumper进行一次全量dump,但不时会遇到dumper没有收到通知的情况。通过查看度假后台的日志,发现在发送全量dump通知的时候抛出了"dead lock detached"的错误,由于后台代码此处并没有采用多线程,进而怀疑是DB死锁,于是请求老何支援。查看DB的错误日志,发现是后台系统和dumper的sql产生了死锁。
死锁原因
产生死锁的两项DB操作分别如下:
1. 度假后台:发送全量dump通知前的数据更新会对名为route的表进行循环update操作,且整个循环被保持在一个事务当中,整个事务成功后才会发送全量dump通知,否则rollback。
2. dumper:dumper除了监听全量dump通知之外,还会对route表中update_flag字段为true的记录进行增量dump,dump完成后会将update_flag重新置为false,使用的sql如下。
update route set update_flag = false where update_flag = true and id in (...);
其中,括号内的id为无序,这也是产生死锁的关键。
假设度假后台代码中是按ID升序更新,更新序列为"1,2,3,4,5,6...",而dumper某次增量dump需要更新ID为3,5的记录,且更新序列为所"5,3",那么将可能出现下面的情况。
度假后台依次更新ID为1,2,3,4的记录,并且获得了这四条记录的行锁,此时需要获取ID为5的记录的行锁;而不巧dumper的update操作正好刚更新完ID为5的记录,正需要获取ID为3的记录的行锁...
于是死锁产生了
解决办法
解决办法很简单,只需要给dumper的"where id in (...)" sql中的ID排个序,且保证其顺序与度假后台事务中的更新顺序一致。这样,上述的死锁情况就会变为:
度假后台需要顺序获得ID为"1,2,3,4,5,6,..."的行锁,dumper则需要顺序获得ID为"3,5"的行锁,无论两项操作谁先开始,都最多只可能有一项操作处于等待锁的状态。
另一种解决方法是,将dumper中的"where id in (...)"操作修改为每个ID执行一条SQL,且该批量更新操作无需保证其事务性。在保证使用同一数据库连接的前提下,拆分开的多个update操作应该不会比之前的"update ...按 where id in (...)"操作慢多少。小插曲:在比较这两种操作的性能时,老何提到说"集中型的操作会造成资源占用的尖峰,如果这个尖峰引起了系统资源的紧张,那么执行的效率或许还不如把操作切分为多个小份,那样每一份操作会很快地执行完"。
后续思考
在了解了死锁产生的原因之后,我对数据库获取和释放行锁的顺序有了一丝疑问:
1.为什么产生死锁的两项操作不会在一开始就把需要的行锁全部拿到,从而杜绝和其他操作产生死锁的可能;
2.为什么释放锁的时候不是用完一个释放一个,而是要等所有操作都进行完了才一起释放?
于是上stackoverflow发了个问(
http://stackoverflow.com/questions/11454638/how-do-the-db-lock-rows-and-release-them).
答案里提到,获取和释放锁的顺序和DB的数据库隔离级别有关。在默认的隔离级别Read Committed下,锁的获取和释放就像问题中所描述的那样,获取的时候会依次获取,而释放则统一在操作完成后释放。如果是使用最为严格的Serializable隔离级别,那么情况就会变成和我第一个疑问中描述的那样:在操作的一开始便把需要的行锁全部拿到,直到操作完成才全部释放,但是这样自然会造成性能的下降。
至于我第二个疑问所描述的情况,则是无法保证事务性的,如果操作还未完成便释放部分行锁的话,其他操作可能会这一部分记录做修改,从而破坏了整个事务。
分享到:
相关推荐
本文将深入探讨一次公司仓库数据库服务器遇到死锁的情况,以及如何通过分析和解决方法来解除死锁。 首先,我们需要理解死锁的基本概念。死锁是指两个或多个进程在执行过程中,因争夺资源而造成的一种相互等待的现象...
标题和描述中提到的事件是一次在线MySQL数据库发生的死锁问题,这突显了了解数据库加锁原理的重要性,而不仅仅是基础的CRUD操作。死锁是指两个或多个事务在执行过程中,因争夺资源而造成的一种相互等待的现象,若无...
4. **程序逻辑优化**:在代码层面避免可能导致死锁的操作,如一次性获取所有需要的锁。 **总结** 了解死锁的原因和排查方法对于后端开发者至关重要。虽然我们不需要深入研究锁的源码,但熟悉基本的死锁原理和排查...
本篇文章将深入探讨一次神奇的MySQL死锁排查记录,通过具体的案例帮助读者理解和解决这类问题。 在描述中提到的背景,我们了解到作者之前对MySQL锁机制有一定的了解,但在处理一个特定的死锁问题时遇到了挑战。问题...
1. **互斥条件**:至少有一个资源必须处于非共享模式,即一次只能被一个进程使用。 2. **请求与保持条件**:一个进程已经持有至少一个资源,但又申请新的资源,而该资源已被其他进程占有,此时请求进程阻塞并保持其...
MySQL数据库中的死锁问题是一个复杂而重要的主题,尤其是在高并发的业务环境中。本文将通过一个具体的实例来深入理解MySQL死锁的产生、检测以及解决策略。 首先,让我们回顾一下这个实例。在2016年11月15日,一个...
第一次实验可能涉及数据库的创建和基本操作。学生会学习如何使用MySQL或Oracle等常见数据库管理系统来建立一个新的数据库,并定义各个表的字段,理解主键、外键、唯一性约束等概念。此外,还会接触到数据类型,如...
如果实例涉及到多线程,那么就需要理解如何在并发环境下安全地访问数据库,避免数据竞争和死锁问题。 10. 数据库设计: 实例可能还会涵盖数据库设计的基本原则,如范式理论,以及如何创建表、索引、视图等数据库...
例如,对于银行系统,可能需要实时处理成千上万的交易,避免死锁和性能下降,例如在电信系统的二次批价和实时累账,或者在ATM监控系统中监控可疑交易。 面对这样的挑战,一种解决方案是使用内存数据库,如h2...
例如银行数据库包含各客户帐户的余额,任何帐户金额的变更都是一次事务的处理。如转账操作:帐户A取款100转帐到帐户B帐户存入100步骤:事务T从A帐户取100¥到B帐户T:read(A);结论:取款和存款两个步骤在一个事务...
但是,如果在备份过程中遇到突发状况,例如长时间未进行系统维护而导致的数据库死锁,就可能导致备份中断。此时,若直接重启数据库服务,可能会引起更严重的问题。 **具体情形:** 笔者所在医院在一次高峰时段,发现...
在IT行业的数据库管理中,遇到“数据库tempdb的日志已满”这一问题是非常常见的,它不仅会影响数据库的性能,还可能导致部分操作无法执行。本文将深入解析这一问题的原因、影响以及解决方案,帮助数据库管理员和开发...
这份实验报告包含了三次实验,分别对应了实验一到实验十,旨在帮助学生深入理解数据库系统的工作原理及其应用。 实验一通常会涉及数据库的基本概念,如关系型数据库模型,SQL语言的介绍,以及ER(实体-关系)模型的...
这不仅是技术上的挑战,也是一次自我学习和反思的机会。学生应能够全面、详细地描述遇到的困难,分享解决问题的经验,以及对课程学习的感受和收获。\n\n总体而言,图书管理系统课程设计涵盖了数据库设计与管理的多个...
- 通过比较备份文件的时间戳,可以判断最近一次备份是否已经按计划执行。 - 如果发现备份时间过期,应立即安排执行备份。 ##### 5.3 检查Oracle用户的EMAIL - **操作**:与第二节中的2.4相同,确保备份过程中的...
在实际数据库运维过程中,我们可能会遇到各种各样的问题,其中死锁是一个较为常见也较为棘手的问题之一。本文将以一个具体的案例为基础,对MySQL Innodb环境下发生的死锁情况进行详细分析和归纳,帮助读者更好地理解...
6. **故障类型**:数据库系统可能遇到的故障主要包括事务故障、系统故障、介质故障和计算机病毒。其中,事务故障和系统故障影响事务执行,介质故障和病毒可能破坏数据库数据。 7. **恢复技术**:数据库恢复通常依赖...
- 核保后保费检查问题:运行作业一次后就算处理完成,但如果有错误发生不会提示,需要进行特定的SQL更新操作以修正。 - 转合同投保单标识问题:如果相关信息为空,则可能导致后台作业无法处理。 - 打印数据产生并...
\n\n- **活锁和死锁**\n活锁和死锁是并发控制中可能遇到的另外两种问题。活锁是事务因等待对方释放资源而无限期等待,死锁则是多个事务互相等待对方资源,导致所有事务都无法继续执行。需要有专门的策略来检测和解决...
数据库是存储数据的容器,表是存储数据的基本结构,视图是基于表的查询结果集,存储过程是一组为了完成特定功能的SQL语句集,函数类似于存储过程,但必须返回一个值,触发器是数据库表中发生特定事件时自动执行的...