事务图谱
事务的特性
原子性(Atomicity)
- 事务中的操作要么全部成功,要么全部失败
- MySQL的两阶段提交保证了事务的原子性
-
一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态
-
隔离性(lsolation)
事务不能被其他事务的操作数据所干扰
- 多个并发事务之间要相互隔离
-
持久性(Durability)
一个事务一旦被提交,它对数据库中数据的改变就是永久性的
- redo log实现了MySQL事务的持久性
隔离级别
读未提交(READ UNCOMMITTED)
- 读、写都不加锁,不隔离
- 每次查询都查询到数据的最新版本
- 性能最好,但是等于没有事务,很少采用
读已提交(READ COMMITTED)
- —般读取时,读取此时已经提交的数据
- 写数据时,加X锁,提交时释放
- Oracle数据库的默认隔离级别
可重复读(REPEATABLE READ)
- 一般读取时,读取本事务开始时的数据
- 状态写数据时,加X锁,提交时释放
- MySQL数据库的默认隔离级别
- MySQL中的可重复读,在写数据加X锁时,另一个事务是可以快照读的。
串行化(SERIALIZABLE)
- 读加S锁、写加X锁,提交时释放
- 对于一条数据,同时只能有一个事务进行写操作
- 事务隔离性最高,性能太差,很少采用
MVCC多版本并发控制
行记录的版本控制
快照读(一致性非锁定读)
不锁定数据的情况下,读取数据的特定历史版本
版本由事务的具体需求确定:
- 读已提交:根据每次SELECT时,其他事务的提交情况
- 可重复读:根据事务开始时,其他事务的提交情况
当前读(一致性锁定读)
- 读取数据的当前版本,并加锁
- 若当前版本已经被加锁且不兼容,则阻塞等待
- X锁:UPDATE、DELETE、SELECT FOR UPDATE
- S锁: SELECT IN SHARE MODE
- SERIALIZABLE所有的读都是当前读,加了S锁
-
MySQL不同隔离级别的问题
脏读:读到了其他事务未提交的数据
不可重复读:同样的查询读到的数据内容不一样
幻读:同样的查询读到了更多的数据,记录的条数不一样
在通用的数据库规范里面,可重复读是不需要解决幻读问题的。
但是MySQL通过间隙锁和Next Key锁的进制,部分解决了幻读的问题。如何解决幻读问题
MySQL在可重复读级别时,通过Next-Key锁解决了幻读问题
- Next-Key锁是行锁+间隙锁
- 间隙锁的功能与行锁相同,只是针对间隙加锁
- 间隙锁不分读写,也可以认为是读锁,不允许在间隙插入
- 可重复读加锁时,将同时锁住数据及其左右间隙
Next-Key Lock的加锁逻辑
- 加锁时以Next-Key为基本单位
Next-Key就是间隙和它的下一个行记录。
- 查找过程中扫描过的范围才加锁
- 唯一索引等值查询,没有间隙锁,只加行锁
- 索引等值查询最右一个扫描到的不满足条件值不加行锁
- 索引覆盖且只加S锁时,不锁主键索引
示例数据表
``sql CREATE TABLE
t3(
idINT (11)NOT NULL,
cINT (11) DEFAULT NULL,
dINT (11)DEFAULT NULL,PRIMARY KEY (
id), KEY
c(
c`) )ENGINE =INNODB;
INSERT INTO t3 VALUES ( 0,0,0 ),(10,10,10 ),( 20,20,20 ),( 30,30, 30 ),( 40,40,40 ),( 50, 50, 50 ); ```
等值查询间隙锁
非唯一索引等值锁
非唯一索引是可能重复的,需要锁住值左右之间的间隙,防止在间隙范围内提交新的数据。
主键索引范围锁
非唯一索引范围锁
不是唯一索引,以Next-Key为单位进行加锁,最终加锁范围是(10,40)
非索引字段查询
注意:当前读时,不要查询没有索引的项目,会锁住整张表。