15事务隔离
读未提交
允许读到未提交数据,查询不使用锁,可能会产生脏读、不可重复读、幻读等情况。读已提交
就是只能读到已经提交的内容,可以避免脏读的产生,属于RDBMS中常见的默认隔离级别(比如说 Oracle和SQL Server),但如果想要避免不可重复读或者幻读,就需要我们在SQL查询的时候编写带加锁的SQL语句(我会在进阶篇里讲加锁)。可重复读(MySQL默认)
保证一个事务在相同查询条件下两次查询得到的数据结果是一致的,可以避免不可重复读和脏读,但无法避免幻读。可串行化
将事务进行串行化,也就是在一个队列中按照顺序执行,可串行化是最高级别的隔离等级,可以解决事务读取中所有可能出现的异常情况,但是它牺牲了系统的并发性。
三个隐藏列:
DB_TRX_ID 事务ID,最后一个对该数据进行插入或更新的事务ID
DB_ROLL_PTR:旧数据指针,指向undolog;
ROW_ID没有主键列时
undolog:记录事务id、对应的操作、当前值
读已提交不是行锁实现的,是MVCC通过undolog实现的,每次查询数据创建ReadView(相同查询也创建新的),通过undolog查询到已提交的数据
ReadView包含三个字段creator_trx_id当前事务,min_trx_id未提交事务, max_trx_id未开始事务,trx_ids当前活跃的事务列表
可见性规则:
- undolog_trx_id < min_trx_id 可见
- undolog_trx_id > max_trx_id 不可见
- min_trx_id < undolog_trx_id < max_trx_id
- 若undolog_trx_id是creator_trx_id,可见
- 若undolog_trx_id在活跃事务数组中,表示事务未提交,不可见
- 若undolog_trx_id不在活跃事务数组中,表示事务已提交,可见
重复读,MVCC控制,相同查询只创建一次ReadView
串行化:表锁
MVCC
通过undolog+readview实现
有隐藏数据行指向undolog,每次启动事务读创建readview指向对应的undolog节点
解决问题
- 读写阻塞
通过MVCC可以让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就可以提升事务并发处理能力。 - 降低死锁概率
MVCC采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。 - 解决一致性读的问题
一致性读也被称为快照读,当我们查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。
快照读、当前读
快照读:不加锁的简单select都属于快照读
如:select * from player where
当前读:读取最新数据,非历史版本数据。加锁select或数据增删改查进行当前读
如:select * from player LOCK IN SHARE MODE (共享锁)
select * from palyer FOR UPDATE (排他锁)
insert into player values … (排他锁)
delete from player where … (排他锁)
update player set … (排他锁)