锁的阻塞,死锁,锁升级

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介: 阻塞因为不同锁之间的兼容性关系,所以在有些时刻,一个事务中的锁需要等待另一个事务中的锁释放它所占用的资源。在InnoDB存储引擎的源代码中,用Mutex数据结构来实现锁。在访问资源前需要用mutex_enter函数进行申请,在资源访问或修改完毕后立即执行mutex_exit函数。

阻塞

因为不同锁之间的兼容性关系,所以在有些时刻,一个事务中的锁需要等待另一个事务中的锁释放它所占用的资源。在InnoDB存储引擎的源代码中,用Mutex数据结构来实现锁。在访问资源前需要用mutex_enter函数进行申请在资源访问或修改完毕后立即执行mutex_exit函数当一个资源已被一个事务占有时,另一个事务执行mutex_enter函数会发生等待,这就是阻塞。阻塞并不是一件坏事,阻塞是为了保证事务可以并发并且正常运行。

在InnoDB存储引擎中,参数innodb_lock_wait_timeout用来控制等待的时间(默认是50秒),innodb_rollback_on_timeout用来设定是否在等待超时时对进行中的事务进行回滚操作(默认是OFF,代表不回滚)。

参数innodb_lock_wait_timeout是动态的,可以在MySQL数据库运行时进行调整,而innodb_rollback_on_timeout是静态的,不可在启动时进行修改,如:

set @@innodb_lock_wait_timeout=60;

set @@innodb_rollback_on_timeout=on;

ERROR 1238(HY000):Variable'innodb_rollback_on_timeout'is a read only variable

当发生超时时,数据库会抛出一个1205的错误,如:

begin;

select * from t where a=1 for update;

ERROR 1205(HY000):Lock wait timeout exceeded;try restarting transaction

需要牢记的是,默认情况下InnoDB存储引擎不会回滚超时引发的错误异常。其实InnoDB存储引擎在大部分情况下都不会对异常进行回滚。

如在一个会话中执行了如下语句:

#会话A

select * from t;

begin;

select * from t where a<4 for update;

会话A中开启了一个事务,Next-Key Lock算法下锁定了小于4的所有记录(其实也锁定了4这个记录)。在另一个会话中执行如下语句:

#会话B

begin;

insert into t select 5;

insert into t select 3;

ERROR 1205(HY000):Lock wait timeout exceeded;try restarting transaction

select * from t;

可以看到,在会话B中插入记录5是可以的,但是插入记录3的话,因为Next-Key Lock算法的关系,需要等待会话A中事务释放这个资源,因此等待后产生了超时。但是在超时后,我们再进行SELECT会发现,5这个记录并没有并回滚。其实这时事务发生了错误,但是既没有commit,也没有rollback,这是十分危险的,用户必须判断是需要commit还是需要rollback,然后再进行下一步操作。

死锁

如果程序是串行的,那么不可能发生死锁。死锁只发生于并发的情况,数据库就是一个并发进行着的程序,因此可能会发生死锁。InnoDB存储引擎有一个后台的锁监控线程,该线程负责查看可能的死锁问题,并自动告知用户。

下面的操作演示了死锁的一种经典的情况,即A等待B,B在等待A:

(for update加的是排他锁)在上述操作中,会话中的事务抛出了1213这个出错提示,即发生了死锁。死锁的原因是会话A和B的资源互相在等待。大多数的死锁InnoDB存储自己可以侦测到,不需要人为进行干预。

但是在上面的例子中,会话B中的事务抛出死锁异常后,会话A中马上得到了记录为2的这个资源,这其实是因为会话B中的事务发生了回滚,否则会话A中的事务是不可能得到该资源的。InnoDB存储引擎并不会回滚大部分的错误异常,但是死锁除外发现死锁后,InnoDB存储引擎会马上回滚一个事务,这点是需要注意的。如果在应用程序中捕获了1213这个错误,其实并不需要对其进行回滚。

Oracle数据库中产生死锁的常见原因是没有对外键添加索引,而InnoDB存储引擎会自动对其进行添加,因此很好地避免了这种情况的发生。人为删除外键上的索引数据库会抛出一个异常:

create table p(a int,primary key(a));

create table c(b int,foreign key(b) references p(a))engine=innodb;

show index from c\G;

drop index b on c;

ERROR 1553(HY000):Cannot drop index 'b':needed in a foreign key constraint

可以看到,虽然在建立子表时指定了外键,但是InnoDB存储引擎还是自动在外键列上建立了一个索引b,而人为删除这个列却是不允许的。

锁升级

锁升级(Lock Escalation)是指将当前锁的粒度降低。举例来说,数据库可以把一个表的1 000个行锁升级为一个页锁,或者将页锁升级为表锁。如果数据库的设计中认为锁是一种稀有资源,而且想避免锁的开销,那数据库中会频繁出现锁升级现象。

Microsoft SQL Server数据库的设计认为锁是一种稀有的资源,在适合的时候会自动地将行、键或者分页级锁升级为更粗粒度的表级锁。这种升级保护了系统资源,防止系统使用太多的内存来维护锁,从一定程度上提高了效率。

即使在Microsoft SQL Server 2005的版本之后,SQL Server数据库支持了行锁,但是其设计和InnoDB存储引擎完全不同,在以下情况下依然可能发生锁升级:

  1. 由一句单独的SQL语句在一个对象上持有的锁数量超过了阈值,默认的这个阈值为5000。值得注意的是,如果是不同对象的话,则不会发生锁升级。
  2. 锁资源占用的内存超过了激活内存的40%时,就会发生锁升级。

在Microsoft SQL Server数据库中,因为锁是一种稀有的资源,因此锁升级会带来一定的效率提高。但是锁升级带来的一个问题却是,因为锁粒度的降低而导致并发性能的降低。

InnoDB存储引擎不存在锁升级的问题。在InnoDB存储引擎中,1个锁的开销与1 000 000个锁是一样的,都没有开销。这一点和Oracle数据库比较类似。

 

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
3月前
多线程并发锁的方案—互斥锁
多线程并发锁的方案—互斥锁
|
4月前
|
存储 安全 Java
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
36 0
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
|
5月前
|
Linux API C++
锁、避免死锁等相关
锁、避免死锁等相关
31 0
|
11月前
|
安全 Java 调度
认识并发中常见的锁
1. 锁的作用 2. 乐观锁和悲观锁 1)乐观锁 2)悲观锁 3)乐观锁和悲观锁在 Java 中的典型实现 4)数据版本机制 3. CAS 机制 1)什么是 CAS 2)CAS 的 ABA 问题 4. 读写锁 1)Java 标准库中提供的读写锁 5. 偏向锁、轻量级锁和重量级锁 1)偏向锁 2)轻量级锁 3)重量级锁 6. 自旋锁 7. 公平锁和非公平锁
90 0
锁消除、锁粗化、锁升级区别与联系
锁消除、锁粗化、锁升级区别与联系
锁消除、锁粗化、锁升级区别与联系
|
PHP
并发锁(二):共享锁和独占锁
并发锁(二):共享锁和独占锁
178 0
并发锁(二):共享锁和独占锁
|
生物认证
什么是锁?
什么是锁?
93 0
什么是锁?
|
安全 Java 调度
【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )
【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )
221 0
【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )