SQl标准定义的四个隔离级别为:
- readuncommited(读未提交)
- readcommited(不可重复读)
- repeatable read(可重复读)
- serializable(串行化)
隔离度有多种实现方式,加锁是其中的一种方式,其理解较为容易且能以开销较小的方式确保数据库系统中并发事物各自运行时,每个事务的运行不受其他事务的影响。
MySQL(InnoDB引擎)中在实现不同级别的隔离度时,核心技术之一就是使用不同粒度的锁。
一、InnoDB中锁的类型介绍
(1)共享锁(Shared Lock(S锁))
共享锁可以允许当前事务读取一行数据,由于读不会改变数据,故各个事务之间可以并发读取数据。当一个事务A获取了行R的共享锁,另外的事务B也可以立即获得行R的共享锁,这种情况称为“锁兼容”。
设置共享锁:SELECT* FROM USERWHEREID = 1 LOCK IN SHAREMODE;
(2)排他锁(ExclusiveLocks(X锁))
加了排他锁的记录,则不允许其他事务再向此数据表加S锁或者X锁。insert、update、delete操作,InnoDB会自动给其加上排他锁,对于select操作需要手动设置排他锁。
设置排他锁:SELECT * FROM USERWHEREID = 1 FOR UPDATE;
共享锁与排他锁之间的兼容性如下:
事务A 事务B | 共享锁 | 排他锁 |
---|---|---|
共享锁 | 兼容 | 不兼容 |
排他锁 | 不兼容 | 不兼容 |
(3)意向共享锁(IS锁)
事务在给数据行加共享锁之前,会给数据行所在表也添加锁,这个表级锁就是意向共享锁。如果需要对记录 A 加共享锁,那么此时 InnoDB 会先找到这张表,对该表加意向共享锁之后,再对记录 A 添加共享锁。
(4)意向排他锁(IX锁)
类似IS锁,事务在给数据行加排他锁前,会对数据行所在表添加意向排他锁。当一个事务对表添加意向排他锁后,另外一个事务在加锁前就会通过该表的意向排他锁得知已经有事务在对该表进行独占操作,从而等待。
可以发现,意向锁是一种表级锁,可较为方便地判断表中是否存在被锁定的数据行。假设意向锁是一种行锁(或不存在意向锁),事务A对表中某一数据行加排他锁且未提交,当事务B欲对该表加表锁时,数据库需逐行判断表中是否存在被锁定的数据行,执行效率很低;但当意向锁作为表锁出现时,只需检查一次表中是否存在意向锁即可判断当前有无锁定的数据行,性能大为提升。
在InnoDB中,意向锁是引擎自动维护的,用户不能对其进行操作,这种锁可看作引擎对加锁性能的优化。
另外,需要注意的是,InnoDB的行锁是实现在索引项上的,所以只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。例如在teacher表中,id是主键(教师编号),但SQL语句中检索条件为教师姓名:select * from teacher where name=‘Zhang Sand’ for update,此时不满足上述行级锁加锁条件,则给整张表加锁。
(5)自增锁(AUTO-INC Locks)
自增锁是一种特殊的表级锁,当一个事务正在向表中插入数据时,其他事务都会被阻塞,确保插入数据的连续自增性。
(6)表级锁的兼容性表
事务A/事务B | 意向共享 | 意向排他 | 表级共享 | 表级排他 | 自增锁 |
---|---|---|---|---|---|
意向共享 | 兼容 | 兼容 | 兼容 | 不兼容 | 兼容 |
意向排他 | 兼容 | 兼容 | 不兼容 | 不兼容 | 兼容 |
表级共享 | 兼容 | 不兼容 | 兼容 | 不兼容 | 不兼容 |
表级排他 | 不兼容 | 不兼容 | 不兼容 | 不兼容 | 不兼容 |
自增锁 | 兼容 | 兼容 | 不兼容 | 不兼容 | 不兼容 |
以上是对MySQL数据库中锁类型的简单介绍,对于锁机制想要有更深了解的读者可参考《MySQL技术内幕-innodb存储引擎》,愿大家在以后的技术道路上都能变得更强!