锁表导致的BUG

一篇关于在服务层方法中执行数据库操作导致程序停滞的文章,通过排查发现是由于更新语句引发的死锁问题。

    昨天写代码的时候,一段原本运行的很好的代码,忽然之间就出了诡异的问题了:在service层的方法中,有一条插入数据库的语句,一条更新数据库的语句(不是同一张表),如果不出异常就返回true,出异常就返回false。症状是:执行完return true之后,即使放过断点,程序也不动了,不继续执行调用他的方法。

 

   我开始的时候以为是IDE的问题,或者是tomcat缓存的问题,于是重新编译了下项目,把tomcat下相关的东西也都清空了,发现还是不好用,本着节约时间的原则,请来同事帮忙。

 

   同事开始的时候,也是向我一样,重新编译,清空……,发现也不好用。经过一系列折腾之后,同事注释掉了service层方法中的那条更新数据库的语句,只运行插入数据库的语句,OK,一切正常。这时候,我好奇心起来了,把插入语句注释掉,只执行更新语句,发现症状又出来了。

 

   这时候基本就可用认为是更新的部分出问题了,于是同事让我把hibernate打印出的SQL放到PL/SQL里面去执行(话说我从来没想过要把更新语句放到PL/SQL里面去执行,更新语句还能出错?),我俩大眼瞪小眼的看了半天,也没发现那条SQL的问题,但是放到PL/SQL里面执行的时候,却死活都是执行中的状态,没个结果。后来终于想到,难道是锁表了?

 

  于是我让DBA帮查下这个表是不是被锁住了?DBA一看,果然被锁了,而且还是N多没有commit的,让DBA杀死这些死锁之后,再运行程序,果然正常了。

 

  同事跟我说:“你去买块豆腐吧”。

 

  只是我想了一个晚上,也没想到这个死锁是怎么开始的呢?

 

 

  总结:

  1、遇到问题不要慌张,不要紧张,不要因为诡异的,自己没见过的问题就认为自己解决不了。这个问题其实是个很简单的问题。

  2、多问问同事也是好的,有利于节省时间,不过不能解决了就解决了,还得自己总结总结,否则下次出现类似的问题还是不会解决。

  3、我之前已经基本不怕系统报告的异常了,但是昨天碰到这种什么反映都没有的情况着实还是怕了一下。以后争取不怕任何问题。

 

 

 

  

<think>首先,用户的问题是关于MySQL的产生原因及机制。我需要基于提供的引用内容来构建回答,同时确保回答结构清晰、真实可靠。 回顾引用内容: - [^1]: 描述了MySQL的原因和解决方法,包括查看阻塞数据、杀死进程、查看被访问的、死异常示例和查看死状态。 - [^2]: 解释了死常见于程序BUG,建议调整逻辑,如按顺序定资源。 - [^3]: 提到了一个脚本,用于检查并杀死定的进程。 - [^4]: 讨论了MySQL + PHP模式下的僵死进程问题,并提到使用脚本自动处理。 用户的问题是:“我想了解MySQL的产生原因及机制 请问MySQL产生的原因及解决方法”。所以,我需要覆盖: 1. 的原因(包括死)。 2. 的机制。 3. 解决方法。 系统指令要求: - 使用中文回答。 - 行内数学达式用$...$,但MySQL相关可能不需要数学公式,除非涉及计算。 - 独立公式用$$...$$,但同样,可能不适用。 - 生成相关问题。 - 回答中引用的段落末尾添加引用标识。 - 结构清晰,逐步解决问题。 回答结构: 1. **引言**:简要介绍的概念。 2. **原因和机制**:详细解释为什么发生,包括死。 3. **解决方法**:提供基于引用的解决方案。 4. **相关问题**:生成相关问题。 关键点从引用中提取: - 原因:程序BUG、资源定顺序不一致、高并发下的僵死进程。 - 机制:InnoDB引擎的死检测、超时。 - 解决方法:杀死进程、调整程序逻辑、使用脚本监控。 确保回答真实可靠:基于引用内容,不要添加未经验证的信息。 生成相关问题:基于用户问题,生成2-3个相关问题。 完整回答: - 开头:直接回答问题。 - 主体:分点解释原因、机制和解决方法。 - 结尾:列出相关问题。</think>### MySQL产生的原因及机制 MySQL数据库管理系统中常见的并发控制问题,主要发生在多个事务同时访问或修改同一数据时。可能导致事务阻塞、性能下降,甚至死。下面我将逐步解释的原因、机制及解决方法,确保回答基于可靠引用。 #### 一、产生的原因 MySQL通常由以下原因引起: 1. **资源竞争**:当多个事务同时请求对同一张或同一行数据进行写操作(如UPDATE、DELETE)时,MySQL会使用来保证数据一致性。如果事务未及时释放,其他事务会被阻塞。例如,在高并发场景下,一个事务长时间持有导致后续事务等待超时(引用[1])。 2. **死(Deadlock)**:这是最常见的原因之一。当两个或多个事务相互等待对方释放资源时,形成循环依赖。例如: - 事务AX,同时请求Y。 - 事务BY,同时请求X。 - 双方都无法继续执行,导致(引用[2])。 死通常由程序逻辑缺陷引起,如未按固定顺序定资源。 3. **程序逻辑错误**:应用程序在操作多个时,未按一致顺序定资源。例如,先A再B,但另一个线程先B再A,这易引发死(引用[2])。 4. **高并发下的僵死进程**:在MySQL + PHP等Web应用模式下,大并发压力可能导致大量僵死进程累积。这些进程持有但未释放,最终导致(引用[4])。 #### 二、的机制 MySQL机制主要基于InnoDB存储引擎(默认引擎),涉及以下关键点: - **类型**:MySQL使用行级(row-level locking)和table-level locking)。行级更细粒度,但死风险更高;定整个,适用于DDL操作(如ALTER TABLE)。 - **死检测与超时**: - InnoDB引擎内置死检测机制。当检测到死时,MySQL会自动终止其中一个事务(通常是影响较小的事务),并抛出错误如 `ERROR 1213 (40001): Deadlock found`(引用[1])。 - 如果请求超时(默认50秒),MySQL会终止事务并报错 `ERROR 1205 (HY000): Lock wait timeout exceeded`(引用[1])。 - **等待机制**:事务在请求时,如果资源被占用,会进入等待状态。您可以通过命令查看: ```sql SHOW OPEN TABLES WHERE In_use > 0; -- 查看被定的(引用[1]) SHOW ENGINE INNODB STATUS; -- 查看最近死详情(引用[1]) ``` 输出会显示定的事务ID、等待时间等信息。 - **僵死进程累积**:在高并发场景下,未正确关闭的数据库连接会导致进程挂起,持续持有。这现为 `show processlist` 命令中的 "Locked" 状态(引用[3])。 #### 三、解决方法 针对问题,以下是实用解决方案,基于实际场景: 1. **立即解除**: - 查找并杀死阻塞进程: ```sql -- 查看阻塞进程 SHOW PROCESSLIST; -- 查找状态为 'Locked' 或 'Waiting for lock' 的进程 -- 假设找到 try_mysql_thread_id=14 的阻塞进程 KILL 14; -- 杀死该进程(引用[1]) ``` 您可以使用脚本自动化此过程,例如定期检查并杀死超时进程(引用[3][4])。 - 查看定的: ```sql SHOW OPEN TABLES WHERE In_use > 0; -- 快速定位被(引用[1]) ``` 2. **预防死**: - **调整程序逻辑**:确保多操作时按固定顺序定资源。例如,总是先A再B,避免交叉依赖(引用[2])。 - **优化事务**:缩短事务执行时间,减少持有时间。例如,将大事务拆分为小事务,并使用 `COMMIT` 及时释放。 - **设置超时**:调整MySQL配置,减少等待时间: ```ini innodb_lock_wait_timeout = 30 -- 将默认50秒缩短至30秒(单位:秒) ``` 3. **监控与自动化**: - 使用脚本监控:在高并发环境中,部署脚本定期检查并清理僵死进程。例如: ```bash # 示例脚本:查找并杀死定的进程 mysql_exec -uroot -p$mysql_pwd -e "SHOW PROCESSLIST" | grep -i "Locked" >> kill_log.txt # 根据日志执行KILL命令(引用[3][4]) ``` - 定期分析死日志: ```sql SHOW ENGINE INNODB STATUS; -- 分析死原因,优化SQL语句(引用[1]) ``` 4. **其他最佳实践**: - 使用索引:确保查询使用索引,减少全扫描(这会增加竞争)。 - 隔离级别调整:将事务隔离级别设置为 `READ COMMITTED`,降低死概率(但需权衡一致性)。 - 避免长事务:在Web应用中,设置连接超时,防止僵死连接。 通过以上方法,大多数问题可有效缓解。如果问题持续,建议分析具体SQL和程序逻辑(引用[2])。 ### 相关问题 1. 如何监控MySQL的发生频率和影响? 2. 在分布式系统中,如何避免MySQL问题? 3. MySQL的行级有什么区别?各自适用什么场景?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值