|
|
|
@ -597,41 +597,54 @@ WHERE A.EMP_SUPV_ID = B.EMP_ID;
|
|
|
|
|
|
|
|
|
|
# 数据库锁
|
|
|
|
|
|
|
|
|
|
从粒度上来说就是**表锁、页锁、行锁**。表锁有意向共享锁、意向排他锁、自增锁等。行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如 `MyISAM`引擎就`不支持行锁`。
|
|
|
|
|
按照锁的粒度进行分类,MySQL主要包含三种类型锁:
|
|
|
|
|
|
|
|
|
|
- **全局锁**:锁的是整个 `database`。由MySQL的**SQL layer**层实现的
|
|
|
|
|
- **表级锁**:锁的是某个 `table`。由MySQL的**SQL layer**层实现的
|
|
|
|
|
- **⾏级锁**:锁的是 `某⾏数据` 或 `⾏之间的间隙`。由某些**存储引擎**实现,如InnoDB
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
按照锁的粒度进行分类,MySQL主要包含三种类型(级别)的锁定机制:
|
|
|
|
|
|
|
|
|
|
- **全局锁**:锁的是整个database。由MySQL的SQL layer层实现的
|
|
|
|
|
- **表级锁**:锁的是某个table。由MySQL的SQL layer层实现的
|
|
|
|
|
- **⾏级锁**:锁的是某⾏数据,也可能锁定⾏之间的间隙。由某些存储引擎实现,⽐如InnoDB
|
|
|
|
|
根据不同的存储引擎,MySQL中锁的特性可以大致归纳如下:
|
|
|
|
|
|
|
|
|
|
| 存储引擎 | 行锁 | 表锁 | 页锁 |
|
|
|
|
|
| -------- | ---- | ---- | ---- |
|
|
|
|
|
| InnoDB | √ | √ | |
|
|
|
|
|
| MyISAM | | √ | |
|
|
|
|
|
| BDB | √ | √ | √ |
|
|
|
|
|
|
|
|
|
|
- **表锁**: 开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低
|
|
|
|
|
- **行锁**: 开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高
|
|
|
|
|
- **页锁**: 开销和加锁速度介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在 InnoDB 存储引擎中:
|
|
|
|
|
|
|
|
|
|
- SELECT 操作的不可重复读问题通过`MVCC`得到了解决
|
|
|
|
|
- UPDATE、DELETE 的不可重复读问题通过`Record Lock`(记录锁)解决
|
|
|
|
|
- INSERT 的不可重复读问题是通过`Next-Key Lock`(临键锁)解决
|
|
|
|
|
- `SELECT` 操作的不可重复读问题通过 `MVCC` 得到了解决
|
|
|
|
|
- `UPDATE`、`DELETE` 的不可重复读问题通过 `Record Lock` (记录锁)解决
|
|
|
|
|
- `INSERT` 的不可重复读问题是通过 `Next-Key Lock` (临键锁)解决
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
按照对数据操作的锁粒度来分:
|
|
|
|
|
按照锁的共享策略来分:
|
|
|
|
|
|
|
|
|
|
- **行级锁**
|
|
|
|
|
- **表级锁**
|
|
|
|
|
- **页级锁**
|
|
|
|
|
- **间隙锁**
|
|
|
|
|
- **共享锁(S锁,Shared Locks)**:读锁。针对同一份数据,多个读操作可以同时进行而不会互相影响
|
|
|
|
|
- **排它锁(X锁,Exclusive Locks)**:写锁。当前写操作没有完成前,它会阻断其他写锁和读锁
|
|
|
|
|
|
|
|
|
|
为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁,这两种意向锁都是表锁:
|
|
|
|
|
|
|
|
|
|
- **意向共享锁(IS锁,Intention Shared Lock)**:当事务准备在某条记录上加S锁时,需要先在表级别加一个IS锁
|
|
|
|
|
- **意向排他锁(IX锁,Intention Exclusive Lock)**:当事务准备在某条记录上加X锁时,需要先在表级别加一个IX锁
|
|
|
|
|
|
|
|
|
|
按照锁的共享策略来分:
|
|
|
|
|
| 请求锁模式是否兼容当前锁模式 | X锁 | IX锁 | S锁 | IS锁 |
|
|
|
|
|
| ---------------------------- | ------ | ------ | ------ | ------ |
|
|
|
|
|
| X锁 | `冲突` | `冲突` | `冲突` | `冲突` |
|
|
|
|
|
| IX锁 | `冲突` | 兼容 | `冲突` | 兼容 |
|
|
|
|
|
| S锁 | `冲突` | `冲突` | 兼容 | 兼容 |
|
|
|
|
|
| IS锁 | `冲突` | 兼容 | 兼容 | 兼容 |
|
|
|
|
|
|
|
|
|
|
- **读锁(共享锁)**:Shared Locks(S锁)。针对同一份数据,多个读操作可以同时进行而不会互相影响
|
|
|
|
|
- **写锁(排它锁)**:Exclusive Locks(X锁)。当前写操作没有完成前,它会阻断其他写锁和读锁
|
|
|
|
|
- **IS锁**:意向共享锁、Intention Shared Lock。当事务准备在某条记录上加S锁时,需要先在表级别加一个IS锁
|
|
|
|
|
- **IX锁**:意向排他锁、Intention Exclusive Lock。当事务准备在某条记录上加X锁时,需要先在表级别加一个IX锁
|
|
|
|
|
若一个事务请求锁模式与当前锁兼容,InnoDB就将请求锁授予该事务;反之,两者不兼容,该事务就要等待锁释放。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -829,11 +842,11 @@ InnoDB 存储引擎提供了个`innodb_autoinc_lock_mode`的系统变量,是
|
|
|
|
|
|
|
|
|
|
- **Record Lock(记录锁)**
|
|
|
|
|
- **Gap Lock(间隙锁)**
|
|
|
|
|
- **Next-Key Lock(间隙锁)**
|
|
|
|
|
- **Next-Key Lock(临键锁)**
|
|
|
|
|
|
|
|
|
|
### Record Lock(记录锁)
|
|
|
|
|
|
|
|
|
|
记录锁就是为**某行**记录加锁,它封锁该行的索引记录:
|
|
|
|
|
记录锁就是为**某行**记录加锁,它封锁该行的**索引记录**:
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
-- id 列为主键列或唯一索引列
|
|
|
|
@ -1130,6 +1143,8 @@ kill trx_mysql_thread_id;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
![InnoDB存储引擎SQL隔离级别锁比较](images/Database/InnoDB存储引擎SQL隔离级别锁比较.png)
|
|
|
|
|
|
|
|
|
|
### Read Uncommitted(读未提交)
|
|
|
|
|
|
|
|
|
|
**即读取到了其它事务未提交的内容**。在该隔离级别,**所有事务都可以看到其他未提交事务的执行结果**。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为**脏读(Dirty Read)**。
|
|
|
|
|