MySQL-锁(四)

MySQL为了解决并发读写的问题,使用了锁机制,并通过锁管理器进行管理,在不同的情况下,对数据进行加锁,并根据场景会有不同颗粒度、不同实现的锁

按锁的颗粒度:

1、表锁,颗粒度最大的锁,实现简单,资源消耗少,加锁也快,不会出现死锁,但是出现表锁,而且时间比较长的话,系统就会像STW一样,后面的操作只能等锁释放,并发很低,常用的InnoDB和MyISAM都支持表锁

2、行锁,颗粒度最小的锁,只针对当前行进行加锁,并发读高,能大大减少数据库操作冲突,但是加锁的开销比较大,加锁慢,操作不当很容易死锁,MyISAM不支持行锁,而InnoDB的行锁有几种:

(1)Record Lock:即行锁,对索引项上锁,其他事务不能修改和删除加锁项,InnoDB会隐式的通过主键进行锁定

(2)Gap Lock:前面提到的间歇锁,对数据的一定范围进行加锁,但不包含索引项本身,其他事务不能在锁范围内插入数据,防止其他事务新增行产生幻读的一种解决方案

(3)Next-key Lock:之前也有提到过,间歇锁+行锁,解决幻读问题,主要是锁的当前行和一个范围

举个例子

idnameage
1zhangsan15
3lisi18
5wangwu50

此时对于age来说的区间为:

(-∞, 15],
(15, 18],
(18, 50],
(50, +∞]

事务1的操作:

更新数据并对数据上行锁

update table set name = 'baka' where age = 18
select * from table where age = 18 for update

事务2的操作:

以下命令会被阻塞,19>18,在(18, 50] 这个区间里

insert into table values(6, 'bashaka', 19)

按锁的分类:

共享锁(Shard Lock,简称S锁):也叫读锁,共享锁可以重复上,但是获得共享锁的事务只能读不能写,如果想上X锁只能等锁释放

排它锁(Exclusive Lock,简称X锁):也叫写锁,上了写锁只允许当前事务读写,其他事务都不能做任何操作,只能等资源释放才能做其他操作

看完上面的定义我们不由思考,DDL操作应该是表锁了,那表锁和行锁如果一起发生,会怎样?如果数据量多的时候,这个性能也太差了,MySQL是怎么解决这种问题的?

意向锁,有意向共享锁(IS)和意向排它锁(IX),所谓的意向并不是只是准备加锁的意思,是一种表级锁的,由数据库引擎维护(我们一般讨论的是InnoDB),SQL语句无需任何修改

我们先看上面的问题,当数据量多且并发量上去的时候,我们会遇到性能的瓶颈,如下:

事务1和事务2,一旦数据被占用了,事务2上锁就会被阻塞,当事务1数据量特别大查询比较慢的时候,这个操作无疑是灾难级的,事务2在加锁时是一条条遍历去判断是否有被锁住,这个执行效率是O(n),所以在数据量大的情况下效率会很低

意向锁是让检查行锁的时间复杂度从O(n)变成O(1),当事务对数据修改前先给表加一个IX锁,再给行增加一个X锁,那么如果此时需要全表扫修改或者操作的时候就不需要每条数据去判断了,只需要等待IX释放即可,而IS可以同时存在多个,IX只能存在一个。

我们看一下锁与锁之间的互斥和兼容

XIXSIS
X互斥互斥互斥互斥
IX互斥兼容互斥兼容
S互斥互斥兼容兼容
IS互斥兼容兼容兼容

意向锁之间都是兼容的,所以对标记录加锁不会因为意向锁产生互斥,行锁竞争就是行锁之间的竞争,意向锁不会参与,但是与表级锁会产生互斥,主要是为了避免用遍历的方式来查看表中的上锁记录

Leave a Reply

Your email address will not be published. Required fields are marked *