1. 事务
1.1 定义
数据库执行一组原子性的 SQL 语句,要么全部执行成功,要么全部执行失败
1.2 特性
- 原子性(Atomicity): 一个事务必须被视为一个不可分割的最小工作单元。整个事务中的所有操作要么全部提交成功,要么全部失败回滚 。回滚机制实现
- 一致性(Consistency): 数据库总是从一个一致性状态转换到另一个一致性状态。锁机制实现
- 隔离性(Isolation)事务的所有操作不受其他事务的影响。锁机制实现
- 持久性(Durability): 一旦事务提交,则所做的所有操作就会永久保存。不会因为其他因素发生改变,如系统崩溃等
1.3 隔离级别
-
读未提交(Read Uncommitted)
- 一个事务可读取另一个事务未提交的数据
- 会出现脏读、不可重复读、幻读问题
- 读取、写入、修改、删除都不加锁
- 一般数据库都不会用
-
读已提交(Read Committed)
- 一个事务可读取另一个事务刚提交的事务
- 会出现不可重复读、幻读问题
- 读取不加锁,新增、修改,删除加锁
- 大多数数据库的默认隔离级别
-
可重复读(Repeatable Read)
- 一个事务多次读取的数据相同
- 会出现幻读
- 读取加锁(MVCC 乐观锁: 解决不可重复读,写入、修改、删除加锁(Next-Key 临键锁:解决幻读)
- MySQL 默认隔离级别
-
串行化(Serializable)
- 事务严格串行执行
- 解决了脏读、不可重复读、幻读等问题。但系统效率低
- 读加共享锁,写加排他锁
- 业务并发的特别少或者没有并发,同时又要求数据及时可靠的话,可以使用这种模式
1.4 读取问题
脏读(Dirty Read):一个事务查询到其他事务修改未提交的数据。
不可重复读(NonRepeatable Read):一个事务多次查询数据不一致。重点在于修改、删除数据
幻读(Phantom Read):一个事务读取到其他事务写入的数据。重点在于写入
1.5 隔离级别与读取问题关系(SQL标准)
隔离级别 | 脏读(Dirty Read) | 不可重复读(NonRepeatable Read) | 幻读(Phantom Read) |
---|---|---|---|
未提交读(Read uncommitted) | 可能 | 可能 | 可能 |
已提交读(Read committed) | 不可能 | 可能 | 可能 |
可重复读(Repeatable read) | 不可能 | 不可能 | 可能 |
可串行化(Serializable ) | 不可能 | 不可能 | 不可能 |
2. 锁(MySQL 5.7 InnoDB)
2.1 整体分类
乐观锁:默认认为数据不会被其他事务操作,对数据不加锁,最终检查是否被其他事务操作了。一般在数据中加版本号(version)来实现。
悲观锁:默认认为数据会被其他事务操作,对数据加锁
2.2 InnoDB 锁分类(悲观锁)
行锁:共享锁(share mode lock: S)、排他锁(exclusive lock: X)、记录锁(record lock)、间隙锁(gap lock)、临键锁(next-key lock)、插入意向锁(insert intention lock)
表锁:意向共享锁(intention share mode lock: IS)、意向排他锁(intention exclusive lock: X)、自增锁 (auto-inc lock)
2.3 锁详情
2.3.1 行锁:锁加在索引上,如果没有索引,就隐式聚集主键索引用来加锁
- 共享锁(share mode lock: S): 允许持有锁的事务读取数据 。 Select ... LOCK IN SHARE MODE
- 排他锁(exclusive lock: X): 允许持有锁的事务修改、删除数据。 Select ... FOR UPDATE
- 记录锁(record lock) : 阻止其他事务写入、修改、删除数据。 Select ... FOR UPDATE
- 间隙锁(gap lock): 锁住两个索引记录之间所有行,或者索引记录之前的或者索引记录之后的所有行。解决幻读问题,只有RR级别才有
- 临键锁(next-key lock): 是记录锁和间隙锁的组合,即会锁住索引记录之间的间隙,也能锁住记录。解决幻读问题,只有RR级别才有
- 插入意向锁(insert intention lock): 是一种Gap锁,不是意向锁,在插入数据时产生。多事务插入同一间隙时产生,多事务同一间隙不同区间时不会发生等待
间隙锁生效场景
- 唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁
- 普通索引不管是锁住单条,还是多条记录,都会产生间隙锁
- 普通索引的间隙,优先以普通索引排序,然后再根据主键索引排序
2.3.2 表锁:
- 意向共享锁(intention share mode lock: IS) : 表示一个事务将要对表的行记录加共享锁(S). Select ... LOCK IN SHARE MODE(深层的作用是当要添加表级读写锁时,能够快速判断是否存在锁冲突,不需要全表扫描行锁的存在,提高效率)
- 意向排他锁(intention exclusive lock: IX): 表示一个事务将要对表的行记录加排他锁(X) . Select ... FOR UPDATE(深层的作用是当要添加表级读写锁时,能够快速判断是否存在锁冲突,不需要全表扫描行锁的存在,提高效率)
- 自增锁 (auto-inc lock)
2.3 表锁组合关系
X、S 表示(LOCK TABLES ... WRITE、LOCK TABLES ... READ)表级锁
X |
IX |
S |
IS |
|
---|---|---|---|---|
X |
Conflict | Conflict | Conflict | Conflict |
IX |
Conflict | Compatible | Conflict | Compatible |
S |
Conflict | Conflict | Compatible | Compatible |
IS |
Conflict | Compatible | Compatible | Compatible |
意向锁(IX、IS)之间组合不会产生冲突
意向锁(IX、IS)与 共享锁(S)组合不会产生冲突
共享锁 (S) 与共享锁 (S) 组合不会产生冲突
其他组合都会出产生冲突