锁冲突分析
2.1 innodb的事务与行锁机制
MySQL的事务支持不是绑定在MySQL服务器本身,而是与存储引擎相关,MyISAM不支持事务、采用的是表级锁,而InnoDB支持ACID事务、 行级锁、并发。MySQL默认的行为是在每条SQL语句执行后执行一个COMMIT语句,从而有效的将每条语句作为一个单独的事务来处理。
2.2 两语句加锁情况
在innodb默认的事务隔离级别下,普通的SELECT是不需要加行锁的,但LOCK IN SHARE MODE、FOR UPDATE及高串行化级别中的SELECT都要加锁。有一个例外,此案例中,语句(1)insert into teamUser_20110121 select * from teamUser会对表teamUser_20110121(ENGINE= MyISAM)加表锁,并对teamUser表所有行的主键索引(即聚簇索引)加共享锁。默认对其使用主键索引。
而语句(2)DELETE FROM teamUser WHERE teamId=$teamId AND titleWeight<32768 AND joinTime<'$daysago_1week'为删除操作,会对选中行的主键索引加排他锁。由于此语句还使用了非聚簇索引KEY `k_teamid_titleWeight_score` (`teamId`,`titleWeight`,`score`)的前缀索引,于是,还会对相关行的此非聚簇索引加排他锁。
2.3 锁冲突的产生
由于共享锁与排他锁是互斥的,当一方拥有了某行记录的排他锁后,另一方就不能其拥有共享锁,同样,一方拥有了其共享锁后,另一方也无法得到其排他锁。所 以,当语句(1)、(2)同时运行时,相当于两个事务会同时申请某相同记录行的锁资源,于是会产生锁冲突。由于两个事务都会申请主键索引,锁冲突只会发生 在主键索引上。
常常看到一句话:在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的。那就说明,单个SQL组成的事务锁是一次获得的。而此案例中,语句(2) 已经得到了主键索引的排他锁,为什么还会申请主键索引的排他锁呢?同理,语句(1)已经获得了主键索引的共享锁,为什么还会申请主键索引的共享锁呢?
死锁记录中,事务一等待锁的page no与事务二持有锁的page no相同,均为218436,这又代表什么呢?
我们的猜想是,innodb存储引擎中获得行锁是逐行获得的,并不是一次获得的。下面来证明。
死锁产生过程分析
要想知道innodb加锁的过程,唯一的方式就是运行mysql的debug版本,从gdb的输出中找到结果。根据gdb的结果得到,单个SQL组成的事 务,从宏观上来看,锁是在这个语句上一次获得的,但从底层实现上来看,是逐个记录行查询,得到符合条件的记录即对该行记录的索引加锁。
Gdb结果演示如下:
(gdb) b lock_rec_lock
Breakpoint 1 at 0×867120: file lock/lock0lock.c, line 2070.
(gdb) c
Continuing.
[Switching to Thread 1168550240 (LWP 5540)]
Breakpoint 1, lock_rec_lock (impl=0, mode=5, rec=0x2aedbe01c1 “789\200″, index=0x2aada734b8, thr=0x2aada74c18) at lock/lock0lock.c:2070
2070 {
Current language: auto; currently c
(gdb) c
Continuing.
Breakpoint 1, lock_rec_lock (impl=0, mode=1029, rec=0x2aedbc80ba “\200″, index=0x2aada730b8, thr=0x2aada74c18) at lock/lock0lock.c:2070
2070 {
(gdb) c
Continuing.
Breakpoint 1, lock_rec_lock (impl=0, mode=5, rec=0x2aedbe01cf “789\200″, index=0x2aada734b8, thr=0x2aada74c18) at lock/lock0lock.c:2070
2070 {
(gdb) c
Continuing.
(说明:”789\200″为非聚簇索引,”\200″为主键索引)
Gdb结果显示,语句(1)(2)加锁的获取记录为多行,即逐行获得锁,这样就解释了语句(2)获得了主键索引锁还再次申请主键索引锁的情况。
由于语句(1)使用了主键索引,而语句(2)使用了非聚簇索引,两个事务获得记录行的顺序不同,而加锁的过程是边查边加、逐行获得,于是,就会出现如下情况:
于是,两个事务分别拥有部分锁并等待被对方持有的锁,出现这种资源循环等待的情况,即死锁。此案例中被检测时候的锁冲突就发现在page no为218436和218103的锁上。
InnoDB 会自动检测一个事务的死锁并回滚一个或多个事务来防止死锁。Innodb会选择代价比较小的事务回滚,此次事务(1)解锁并回滚,语句(2)继续运行直至事务结束。
innodb死锁形式归纳
死锁产生的四要素:互斥条件:一个资源每次只能被一个进程使用;请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;不剥夺条件:进程 已获得的资源,在末使用完之前,不能强行剥夺;循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
Innodb检测死锁有两种情况,一种是满足循环等待条件,还有另一种策略:锁结构超过mysql配置中设置的最大数量或锁的遍历深度超过设置的最大深度 时,innodb也会判断为死锁(这是提高性能方面的考虑,避免事务一次占用太多的资源)。这里,我们只考虑满足死锁四要素的情况。
死锁的形式是多样的,但分析到innodb加锁情况的最底层,因循环等待条件而产生的死锁只有可能是四种形式:两张表两行记录交叉申请互斥锁、同一张表则存在主键索引锁冲突、主键索引锁与非聚簇索引锁冲突、锁升级导致的锁等待队列阻塞。
以下首先介绍innodb聚簇索引与非聚簇索引的数据存储形式,再以事例的方式解释这四种死锁情况。
4.1聚簇索引与非聚簇索引介绍
聚簇索引即主键索引,是一种对磁盘上实际数据重新组织以按指定的一个或多个列的值排序,聚簇索引的索引页面指针指向数据页面。非聚簇索引(即第二主键索 引)不重新组织表中的数据,索引顺序与数据物理排列顺序无关。索引通常是通过B-Tree数据结构来描述,那么,聚簇索引的叶节点就是数据节点,而非聚簇 索引的叶节点仍然是索引节点,通常是一个指针指向对应的数据块。
而innodb在非聚簇索引叶子节点包含了主键值作为指针。(这样是为了减少在移动行或数据分页时索引的维护工作。)其结构图如下:
当使用非聚簇索引时,会根据得到的主键值遍历聚簇索引,得到相应的记录。
4.2四种死锁情况
在InnoDB中,使用行锁机制,于是,锁通常是逐步获得的,这就决定了在InnoDB中发生死锁是可能的。
即将分享的四种死锁的锁冲突分别是:不同表的相同记录行索引锁冲突、主键索引锁冲突、主键索引锁与非聚簇索引锁冲突、锁升级造成锁队列阻塞。
不同表的相同记录行锁冲突
案例:两个表、两行记录,交叉获得和申请互斥锁
条件:
A、 两事务分别操作两个表、相同表的同一行记录
B、 申请的锁互斥
C、 申请的顺序不一致
主键索引锁冲突
案例:本文案例,产生冲突在主键索引锁上
条件:
A、 两sql语句即两事务操作同一个表、使用不同索引
B、 申请的锁互斥
C、 操作多行记录
D、 查找到记录的顺序不一致
主键索引锁与非聚簇索引锁冲突
案例:同一行记录,两事务使用不同的索引进行更新操作
此案例涉及TSK_TASK表,该表相关字段及索引如下:
ID:主键;
MON_TIME:监测时间;
STATUS_ID:任务状态;
索引:KEY_TSKTASK_MONTIME2 (STATUS_ID, MON_TIME)。
条件:
A、 两事务使用不同索引
B、 申请的锁互斥
C、 操作同一行记录
当执行update、delete操作时,会修改表中的数据信息。由于innodb存储引擎中索引的数据存储结构,会根据修改语句使用的索引以及修改信息 的不同执行不同的加锁顺序。当使用索引进行查找并修改记录时,会首先加使用的索引锁,然后,如果修改了主键信息,会加主键索引锁和所有非聚簇索引锁,修改 了非聚簇索引列值会加该种非聚簇索引锁。
此案例中,事务一使用非聚簇索引查找并修改主键值,事务二使用主键索引查找并修改主键值,加锁顺序不同,导致同时运行时产生资源循环等待。
锁升级造成锁队列阻塞
案例:同一行记录,事务内进行锁升级,与另一等待锁发送锁队列阻塞,导致死锁
条件:
A、 两事务操作同一行记录
B、 一事务对某一记录先申请共享锁,再升级为排他锁
C、 另一事务在过程中申请这一记录的排他锁
避免死锁的方法
InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句提供非锁定读。这些特色增加了多用户部署和性能。
但其行锁的机制也带来了产生死锁的风险,这就需要在应用程序设计时避免死锁的发生。以单个SQL语句组成的隐式事务来说,建议的避免死锁的方法如下:
1.如果使用insert…select语句备份表格且数据量较大,在单独的时间点操作,避免与其他sql语句争夺资源,或使用select into outfile加上load data infile代替 insert…select,这样不仅快,而且不会要求锁定
2. 一个锁定记录集的事务,其操作结果集应尽量简短,以免一次占用太多资源,与其他事务处理的记录冲突。
3.更新或者删除表格数据,sql语句的where条件都是主键或都是索引,避免两种情况交叉,造成死锁。对于where子句较复杂的情况,将其单独通过sql得到后,再在更新语句中使用。
4. sql语句的嵌套表格不要太多,能拆分就拆分,避免占有资源同时等待资源,导致与其他事务冲突。
5. 对定点运行脚本的情况,避免在同一时间点运行多个对同一表进行读写的脚本,特别注意加锁且操作数据量比较大的语句。
6.应用程序中增加对死锁的判断,如果事务意外结束,重新运行该事务,减少对功能的影响。
相关推荐
#### 锁冲突分析 ##### Innodb的事务与行锁机制 在MySQL的InnoDB存储引擎中,事务支持ACID特性,采用的是行级锁。这意味着在同一时刻,对于某个特定的数据行,多个事务可能需要对该行进行不同的锁定,以确保数据的...
本文将通过实例分析这两种锁在ThinkPHP框架中的应用,以及它们各自的优缺点。 首先,让我们从乐观锁开始了解。乐观锁机制假设多个事务在处理数据时很少发生冲突,因此,它不会在事务开始时就加锁,而是进行数据的...
通过理解这个机制,调整备份计划,以及掌握锁等待问题的分析技巧,我们可以有效地避免这种冲突,确保数据库的稳定运行。对于DB2管理员来说,理解并处理这类问题的能力是日常维护工作中不可或缺的技能。
锁升级是指当数据库系统检测到同一资源上的锁冲突频繁发生时,会自动将较低级别的锁(如行锁)升级为较高级别的锁(如表锁),以减少锁竞争和等待时间,从而提高整体的并发性能。 **1.2 锁升级的影响** 虽然锁升级...
Hibernate,作为Java领域广泛使用的ORM框架,提供了一种处理并发数据访问冲突的手段,那就是锁机制。主要分为两种类型:乐观锁(Optimistic Locking)和悲观锁(Pessimistic Locking)。 **悲观锁(Pessimistic ...
锁是一种软件机制,用于防止多个用户在同一时间对同一资源进行冲突操作,确保数据的一致性和完整性。在SQL Server中,锁的粒度可以是多级别的,包括数据库、表、区域、页面、键值(索引行)和行标识符(RID),这...
当多个用户并发地访问和操作数据库中的数据时,如果没有适当的控制,可能会导致数据的不一致性和冲突。为了解决这个问题,Oracle数据库引入了锁的概念。 在Oracle中,锁主要分为两大类型:排它锁(Exclusive Locks...
### MSSQLServer数据库事务锁机制分析 #### 一、引言 锁机制是数据库系统中一个非常关键的概念,尤其在多用户环境中,它确保了数据的一致性和完整性。不同的数据库管理系统(DBMS)虽然有着相似的基本锁理论,但在...
表锁的特点是开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发度较低。 案例分析 创建一个名为 mylock 的表,使用 MyISAM 存储引擎,插入五条数据。然后,使用 lock table 语句给 mylock 表加读锁...
#### 锁冲突分析 1. **InnoDB事务与行锁机制**:InnoDB支持事务处理,并提供行级锁定。MySQL默认在每条SQL语句执行后提交事务,确保每条语句独立执行。 2. **两语句加锁情况**: - **语句(1)**:`INSERT ... ...
3. 锁冲突及防止办法: 在数据库系统中,死锁是指多个事务各自锁定了某个资源,又试图去锁定对方已锁定的资源,从而形成了一个互相等待的锁定请求环。这会导致所有涉及的事务都无法继续进行,因为它们都在等待对方...
乐观锁假设并发冲突较少,只在更新时检查冲突,而悲观锁在读取数据时就假设会有冲突,采取加锁措施。 总的来说,分布式锁是分布式系统中不可或缺的一部分,它通过协调各个节点对共享资源的访问,保证了系统的稳定性...
这些视图可以帮助识别导致锁冲突的会话信息,查看引起冲突的SQL语句,以及定位被锁定的数据对象。例如,通过`v$session`视图,可以找出持有特定表锁的会话,通过`v$lock`可以查看当前的锁状态。 处理锁冲突: 解决...
【MS SQL SERVER动态锁分析与应用】 SQL SERVER是一款广泛应用的关系型数据库管理系统,其动态锁机制是确保多用户环境下数据一致性和安全性的关键技术。动态锁在SQL SERVER中扮演着至关重要的角色,它能够自动选择...
此外,通过EXPLAIN PLAN和SQL Trace等工具分析SQL执行过程中的锁等待情况,进一步优化查询。 八、总结 Oracle的锁机制是保证数据库安全和性能的重要手段,理解并合理使用锁能有效提升系统并发性,防止数据不一致。...
为了有效地解决这类问题,本文详细介绍了一种查找并定位产生锁冲突的进程、位置、类型以及被锁定表的方法。 #### 查找和定位冲突锁的方法 ##### 1. 首先查看所有的锁信息 根据已有的锁信息量的不同,查找的方法也...
6. **性能分析**:通过模拟并发场景,对比使用乐观锁和悲观锁时的性能差异,理解在不同业务场景下选择合适锁策略的重要性。 7. **实战演练**:设计并执行一系列测试用例,包括正常更新、并发冲突等,以加深对乐观锁...