数据库:MySQL的锁定机制

MySQL通过锁来防止数据并发操作过程中引起的问题。就是防止其他事务访问指定资源的手段,它是实现并发控制的方法,是多个用户能够同时同一个数据库中的数据而不发生数据不一致性现象的重要保障。在MySQL中有3种锁定机制:表级锁定、行级锁定和页级锁定。

表级锁定

表级锁定是MySQL中粒度最大的一种锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的是MyISAM与InnoDB都支持表级锁定,其中MyISAM使用的就是表级锁定。表级锁定的类型包括两种:

  • 读锁。MySQL中用于READ(读)的表级锁定的实现机制如下:如果表没有加写锁,就加一个读锁,否则,将请求放到读锁队列中。

  • 写锁。MySQL中用于WRITE(写)的表级锁定的实现机制如下:如果表没有加锁,就加一个写锁,否则,将请求放到写锁队列中。

行级锁定

行级锁定并不是由MySQL提供的锁定机制,而是由存储引擎自己实现的,其中InnoDB的锁定机制就是行级锁定。行级锁定的类型包括3种:

  • 排他锁(eXclusive Locks)。排他锁又称为X锁。如果事务T1获得了数据行R上的排他锁,则T1对数据行既可读又可写。事务T1对数据行R加上排他锁后,其他事务对数据行R的任务封锁请求都不会成功,直至事务T1释放数据行R上的排他锁。

  • 共享锁(Share Locks)。共享锁又称为S锁。如果事务T1获得了数据行R上的共享锁,则T1对数据项R可以读但不可以写。如果事务T1对数据行R加上共享锁,则其他事务对数据行R的排他锁请求不会成功,而对数据行R的共享锁请求可以成功。

  • 意向锁。意向锁是一种表锁,锁定的粒度是整张表,分为意向共享锁(IS)和意向排他锁(IX)两类。意向锁表示一个事务有意对数据上共享锁或排他锁。

    • 意向共享锁(IS)。事务打算给数据行加共享锁,事务在取得一个数据行的共享锁之前必须先取得该表的IS锁。

    • 意向排他锁(IX)。事务打算给数据行加排他锁,事务在取得一个数据行的排他锁之前必须先取得该表的IX锁。

XIXSIS
X冲突冲突冲突
IX冲突兼容冲突
S冲突冲突兼容
IS冲突兼容兼容

如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待释放。意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给数据集加排他锁;对于SELECT语句,InnoDB不会加任何锁;但是可以通过以下语句,显式地给记录集加共享锁或排他锁。

共享锁: SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE;
排他锁: SELECT * FROM table_name WHERE ... FOR UPDATE;

用SELECT…IN SHARE MODE获得共享锁,主要用在需要数据依存关系时确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁。对于锁定记录后需要进行更新操作的应用,应该使用SELECT…FOR UPDATE方式获得排他锁。

InnoDB的行级锁定是在指向数据记录的第1个索引键之后和最后一个索引键之后的空域空间上标记锁定信息,这种锁定方式被称为“间隙锁”。这种锁定机制是通过索引来实现的,也就是说,无法利用索引时,InnoDB会放弃使用行级锁定而改用表级锁定。

页级锁定

BDB表支持页级锁定。页级锁定的开锁时间和加锁时间介于表级锁定和行级锁定之间,会出现死锁,锁定粒度介于表级锁定和行级锁定之间。

活锁和死锁
活锁

如果事务T1封锁了数据R,事务T2又请求封锁R,于是T2等待。T3也请求封锁R,当T1释放了R上的封锁之后,系统首先批准了T3的请求,T2仍然等待,然后T4又请求封锁R,当T3释放了R上的封锁之后,系统又批准了T4的请求,…,T2有可能永远等待,这就是活锁的情形。避免活锁的简单方法是采用先来先服务的策略。

死锁

两个或两个以上的事务分别申请封锁对方已经封锁的数据对象,导致长期等待而无法继续运行下去的现象称为死锁

# 死锁状态
任务T1具有资源R1的锁,并请求资源R2的锁。
任务T2具有资源R2的锁,并请求资源R1的锁。

两个用户分别锁定一个资源,之后双方又都等待双方释放锁定的资源,产生一个锁定请求环,从而出现死锁现象。死锁会造成资源大量浪费,甚至会使系统奔溃。死锁往往在行级锁定中出现,两个线程互相等待对方的资源释放之后才能释放自己的资源,这样就造成了死锁。

在InnoDB的事务管理和锁定机制中,有专门用于检测死锁的机制。当检测到死锁时,InnoDB会选择产生死锁的两个事务中较小的一个产生回滚,而让另外一个较大的事务成功完成。那么如何判断事务的大小呢?主要是通过计算两个事务各自插入、更新或者删除的数据量来判断,也就是说,哪个事务改变的记录数多,在死锁中就越不会被回滚。需要注意的是,在产生死锁的场景中涉及不止InnoDB存储引擎时,InnoDB是检测不到该死锁的,这时只能通过锁定超时限制来解决该死锁了。

(最近更新:2019年09月03日)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值