【MySql】MySQL产生死锁的根本原因及解决方法
概念
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等的进程称为死锁进程
一、 什么是死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等的进程称为死锁进程.
二、 死锁产生的四个必要条件
互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放
请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放
不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放
环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁
三、 如何处理死锁
1) 锁模式
1. 共享锁(S):由读操作创建的锁,防止在读取数据的过程中,其它事务对数据进行更新;其它事务可以并发读取数据。共享锁可以加在表、页、索引键或者数据行上。在SQL SERVER默认隔离级别下数据读取完毕后就会释放共享锁,但可以通过锁提示或设置更高的事务隔离级别改变共享锁的释放时间。 2. 独占锁(X):对资源独占的锁,一个进程独占地锁定了请求的数据源,那么别的进程无法在此数据源上获得任何类型的锁。独占锁一致持有到事务结束。 3. 更新锁(U):更新锁实际上并不是一种独立的锁,而是共享锁与独占锁的混合。当SQL SERVER执行数据修改操作却首先需要搜索表以找到需要修改的资源时,会获得更新锁。更新锁与共享锁兼容,但只有一个进程可以获取当前数据源上的更新锁,其它进程无法获取该资源的更新锁或独占锁,更新锁的作用就好像一个序列化阀门(serialization gate),将后续申请独占锁的请求压入队列中。持有更新锁的进程能够将其转换成该资源上的独占锁。更新锁不足以用于更新数据—实际的数据修改仍需要用到独占锁。对于独占锁的序列化访问可以避免转换死锁的发生,更新锁会保留到事务结束或者当它们转换成独占锁时为止。 4. 意向锁(IX,IU,IS):意向锁并不是独立的锁定模式,而是一种指出哪些资源已经被锁定的机制。如果一个表页上存在独占锁,那么另一个进程就无法获得该表上的共享表锁,这种层次关系是用意向锁来实现的。进程要获得独占页锁、更新页锁或意向独占页锁,首先必须获得该表上的意向独占锁。同理,进程要获得共享行锁,必须首先获得该表的意向共享锁,以防止别的进程获得独占表锁 5. 特殊锁模式(Sch_s,Sch_m,BU):SQL SERVER提供3种额外的锁模式:架构稳定锁、架构修改锁、大容量更新锁 6. 转换锁(SIX,SIU,UIX):转换锁不会由SQL SERVER 直接请求,而是从一种模式转换到另一种模式所造成的。SQL SERVER 2008支持3种类型的转换锁:SIX、SIU、UIX.其中最常见的是SIX锁,如果事务持有一个资源上的共享锁(S),然后又需要一个IX锁,此时就会出现SIX 7. 键范围锁:键范围锁是在可序列化隔离级别中锁定一定范围内数据的锁。保证在查询数据的键范围内不允许插入数据1234567
2) 锁粒度
SQL SERVER 可以在表、页、行等级别锁定用户的数据资源即非系统资源(系统资源是用闩锁来保护的)。此外SQL SERVER 还可以锁定索引键和索引键范围。通过sys.dm_tran_locks视图可以查看谁被锁定了(如行,键,页)、锁的模式以及特定资源的标志符。基于sys.dm_tran_locks视图创建如下视图用于查看锁定的资源以及锁模式(通过这个视图可以查看事务锁定的表、页、行以及加在数据资源上的锁类型)
3) 如何跟踪死锁
通过选择sql server profiler 事件中的如下选项就可以跟踪到死锁产生的相关语句
4) 死锁案例分析
在该案例中process65db88, process1d0045948为语句1的进程,process629dc8 为语句2的进程; 语句2获取了1689766页上的更新锁,在等待1686247页上的更新锁;而语句1则获取了1686247页上的更新锁在等待1689766页上的更新锁,两个语句等待的资源形成了一个环路,造成死锁
5) 如何解决死锁
针对如上死锁案例,分析其对应语句执行计划如下:通过执行计划可以看出,在查找需要更新的数据时使用的是索引扫描,比较耗费性能,这样就造成锁定资源时间过长,增加了语句并发执行时产生死锁的概率。
处理方式:
1. 在表上建立一个聚集索引。
2. 对语句更新的相关字段建立包含索引。
优化后该语句执行计划如下:优化后的执行计划使用了索引查找,将大幅提升该查询语句的性能,降低了锁定资源的时间,同时也减少了锁定资源的范围,这样就降低了锁资源循环等待事件发生的概率,对于预防死锁的发生会有一定的作用。死锁是无法完全避免的,但如果应用程序适当处理死锁,对涉及的任何用户及系统其余部分的影响可降至最低(适当处理是指发生错误1205时,应用程序重新提交批处理,第二次尝试大多能成功。一个进程被杀死,它的事务被取消,它的锁被释放,死锁中涉及到的另一个进程就可以完成它的工作并释放锁,所以就不具备产生另一个死锁的条件了。)
四、 如何预防死锁
阻止死锁的途径就是避免满足死锁条件的情况发生,为此我们在开发的过程中需要遵循如下原则:
尽量避免并发的执行涉及到修改数据的语句
要求每一个事务一次就将所有要使用到的数据全部加锁,否则就不允许执行.
预先规定一个加锁顺序,所有的事务都必须按照这个顺序对数据执行封锁。如不同的过程在事务内部对对象的更新执行顺序应尽量保证一致
每个事务的执行时间不可太长,对程序段的事务可考虑将其分割为几个事务。在事务中不要求输入,应该在事务之前得到输入,然后快速执行事务
使用尽可能低的隔离级别
数据存储空间离散法。该方法是指采用各种手段,将逻辑上在一个表中的数据分散的若干离散的空间上去,以便改善对表的访问性能。主要通过将大表按行或者列分解为若干小表,或者按照不同的用户群两种方法实现
编写应用程序,让进程持有锁的时间尽可能短,这样其它进程就不必花太长的时间等待锁被释放
猜你喜欢
- 【MySQL】MySql中的锁(表锁,行锁)
- 锁是计算机协调多个进程或纯线程并发访问某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所在有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。 概述 相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。My
- 【MySql】json字段内数据求和
- 首先,我们需要使用JSON_EXTRACT函数来解析JSON数据。假设我们的数据表名为data_table,JSON数据字段名为json_data,需要查询的字段为field_name。```sql SELECT JSON_EXTRACT(json_data, '$.field_name') AS extracted_field FROM data_table;### 步骤2:使用JSON函数提取数组内字段 如果字段是一
- 【MySQL】 复合查询 | 内外连接
- 文章目录1. 复合查询unionunion all单行子查询多行子查询多列子查询in关键字all关键字any关键字多表笛卡尔积自连接在where子句使用子查询在from子句中使用子查询合并查询2. 内连接3. 外连接左外连接右外连接1. 复合查询多表笛卡尔积显示雇员名、雇员工资以及所在部门的名字由于员工 信息属于 emp表 而所在部门名字属于 dept表 数据来自不同的表,所以需要进行多表查询表示从 emp (员工表) 和dept (部门表)
- 【MySql】MySQL表的内外连接和视图
- 内外连接一、表的内外连接(1)左外连接(2)右外连接1. 内连接2. 外连接3. 练习二、视图1. 视图的使用2. 视图规则和限制一、表的内外连接表的连接分为内连和外连。1. 内连接内连接实际上就是利用 where 子句对两种表形成的笛卡尔积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。语法: select 字段 from 表1 inner join 表2 on 连接条件&nbs
- 【MySql】深入解析数据库索引
- 写在前面 MySQL索引是数据库中一个关键的概念,它可以极大地提高查询性能,加快数据检索速度。但是,要充分发挥索引的作用,需要深入理解它们的工作原理和使用方式。在本文中,我们将深入解析MySQL索引,探讨它们的重要性、类型、创建、维护以及最佳实践。一、基础介绍 1.1 什么是索引?在数据库中,索引是一种数据结构,用于快速查找表中的数据。索引包含表中一列或多列的值,这些值按照一定的顺序进行排序,以便优化数据的检索速度。通过使用索引,数据库可以避免全表扫描,从而提高查询
- 【MySql】mysql explain 查询详解
- MySQL 的 EXPLAIN 语句是一个强大的工具,用于分析和优化查询的执行计划。它提供了关于 MySQL 如何执行查询的详细信息,包括表的访问顺序、访问方法、使用的索引、连接类型等。以下是 EXPLAIN 查询的详细解释:
- 【MySql】mysql如何正确设置主键?
- 文章目录主键:如何正确设置主键?业务字段做主键自增字段做主键手动赋值字段做主键主键总结主键:如何正确设置主键?前面我们在讲解存储的时候,有提到过主键,它可以唯一标识表中的某一条记录,对数据表来说非常重要。当我们需要查询和引用表中的一条数据记录的时候,最好的办法就是通过主键。只有合理地设置主键,才能确保我们准确、快速的找到所需要的数据记录。下面我们借助超市项目的实际需求,来讲解一下怎么正确设置主键?在超市项目中,店家想进行会员营销,相应的,我们就需要处理会员信息。会员信息表(demo.member
- 【MySql】mysql 将数据库中的所有表结构和数据 导入到另一个库(亲测有效)
- 一、问题描述在本地开发一个功能,需要结合具体数据测试代码是否正确,但服务器上的数据不可随便修改。此时则需要将服务器上某个数据库的表批量导入到本地、而后进行测试。将数据库db1中的所有表及数据(如table1、table2),批量导入到另一个数据库db2中。二、解决方案刚开始自己一直尝试用DataGrip、Navicat的sql/csv格式导入导出,总有错误或者遗漏,比如报错中止、50张表却只导入32张等,可能是操作方式有误或者数据格式有问题。也试过用sql语句,但仍失败。经查阅资料、尝试多次,终