MySQL 锁

        在之前的文章有多次提到,MySQL在数据更新和性能优化上会用到锁机制。我们在实际的应用中也经常会遇到锁相关的问题,即使很多时候我们并没有人为的为数据库添加锁,但还是会出现死锁的问题,这是因为在我们操作数据时MySQL隐式的帮我们加了锁。这篇文章主要讲一下MySQL锁的类型和锁与锁之间的关联。

MySQL 锁_第1张图片

锁类型

按照操作类型划分:读锁、写锁。

1. 读锁

        读锁也叫共享锁(S 锁),它是一种读共享写阻塞的锁,当对表里的某一行数据添加S锁时,其他事务对其写时会阻塞,但可以对它进行读操作。同时其他事务可以对该数据添加S锁,但不能添加X锁。因此S锁和S锁可兼容,S锁和X锁不能兼容。

2. 写锁

        写锁也叫排他锁(X 锁),它是一种对任何锁都阻塞的锁,当对表里的某行数据添加X锁时,其他事务时不允许再对它添加S锁和X锁。

3. 意向锁

        意向锁是表级锁,又分为意向读锁(IS 锁)和意向写锁(IX 锁),它是基于在InnoDB存储引擎下的一种锁,意向锁无法手工添加,是由存储引擎自动添加的。

        当事务操作需要获取数据行的锁时,首先需要先获取表对应的意向锁。当需要对表添加表级的锁时,会判断是否存在意向锁,而不用每一行判断是否有行锁,这样可以大大提高数据库的性能。
        意向锁之间是相互兼容的,它们相互之间不会阻塞对方获取锁。

按照颗粒度划分:表锁、行锁、间隙锁

1. 表锁

        针对表操作的锁,MyISAM存储引擎下目前只支持表锁。对表进行加锁,加锁速度快、锁的颗粒大、不会出现死锁。但是容易出现锁冲突,性能要低,容易造成阻塞,并发度低。

2. 行锁

        针对数据行操作的锁,InnoDB存储引擎下支持表锁和行锁。加锁的速度慢需要查找到对应的数据行,锁颗粒度小,容易出现死锁,并发度高。当需要对数据进行检索操作时最好能够使用索引,避免全表扫描,如果是全表扫描那么行锁即变为表锁。

3. 页锁

        针对数据页操作的锁,是基于BerkeleyDB存储引擎的锁,锁定的颗粒度介于行锁与表锁之间,所以它的并发度和资源的开销也是介于行锁与表锁之间。

4. 间隙锁

        当检索条件为范围检索,并对检索的结果进行加锁,InnoDB会对当前检索出来已有的数据加锁,并对检索范围内不存在记录的间隙也加锁,这就叫间隙锁。

        举例:

        user表:

id name age
1 张三 18
2 李四 30

      1. 当使用精确检索时

        事务1:

        select * from user where age=18 and age=30 for update;

        事务2:

        insert into user(name,age) values('王五',20);

        这种情况下事务1精确检索,只会对这两行数据进行加锁,因此事务2可正常执行。

        2. 当使用范围检索时

        事务1:

        select * from user where age>=18 and age<=30 for update;

        事务2:

        insert into user(name,age) values('王五',20);

       事务1使用范围检索,InnoDB会对这两行数据进行加锁同时也会对18到30之间的间隙也加锁,因此事务2将会阻塞不可执行。

        间隙锁的引入是为了解决在RR隔离级别的幻读问题。

锁之间兼容性

共享锁 排他锁 意向共享锁 意向排他锁
共享锁 兼容 互斥 兼容 互斥
排他锁 互斥 互斥 互斥 互斥
意向共享锁 兼容 互斥 兼容 兼容
意向排他锁 互斥 互斥 兼容 兼容

       从以上表格中可以看出排他锁与任何锁都不兼容,共享锁只与共享锁兼容,意向锁之间都兼容。

死锁

        死锁是指多个事务在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将一直处于等待状态。

        可以通过以下语句查看锁的状态,最终找到相应产生死锁相应的进程,人工kill该进程释放锁的状态。

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

总结

        MySQL中存在不同颗粒度的锁,从小到大有,行锁、间隙锁、页锁、表锁,锁的颗粒度越大消耗的资源越小,但并发度越低。不同的存储引擎对锁的实现也不一样。InnoDB支持行锁、间隙锁和表锁,MyISAM只支持表锁,BerkeleyDB支持页锁和表锁。

        锁的添加是需要消耗资源的,如果锁添加的越多性能就会相应的降低,同时也会出现锁冲突或者是死锁的情况,所以在实际的应用中根据实际情况加锁,不要盲目的添加从而造成系统性能降低甚至崩溃。

你可能感兴趣的:(mysql,mysql,数据库)