事务特性
- 原子性:要么全完成,要么全不完成
- 一致性:事务前后,数据满足完整性约束
- 隔离性:多个并发事务之间不干扰
- 持久性:事务结束后,对数据修改是持久的
MyISAM
是没有事务的,InnoDB
才有事务,其通过如下方式保证:
- 持久性:
redo log
- 原子性:
undo log
- 隔离性:
MVCC
- 一致性:上面三个特性保证这一个
事务的隔离级别
并行事务问题
并行事务会发生以下情况:
- 脏读:事务A读到了事务B的修改,但是事务B回滚了
- 不可重复读:事务A在前后两次读取同一个数据,第一次读取时事务B还没修改,第二次读取时事务B已经修改并提交了,两次结果不一样
- 幻读:事务A在前后两次通过条件查询,第一次读取时事务B还没有修改,第二次读取时事务B已经修改并提交了,两次结果不一致
PS:不可重复读和幻读最大区别在于是否使用条件查询,不可重复读是对具体数据而言的,幻读是对统计数据而言的,脏读是对回滚事务而言的。三者严重性排序:脏读>不可重复读>幻读
隔离级别
- 读未提交:事务还没提交,就可以被其他事务读取了,可能会发生
脏读、不可重复读、幻读
- 读已提交:事务提交后,才能被其他事务读取,可能会发生
不可重复读、幻读
- 可重复读:事务执行过程中,跟启动事务时的数据一致,可能会发生
幻读
,MySQL InnoDB
默认隔离级别 - 串行化:对记录加上锁,如果有读写冲突,只能一个事务来操作。不会发生上面三种情况,但是效率太低。
虽然Inno DB
是可重复读级别,但是很小概率才会发生幻读问题。
MVCC
Read View
Read View是Inno DB
进行事务的基础结构,它结构如下:
- 行存储结构中就有
trx_id
,就是用于MVCC
的,同样,行存储中还有历史版本指针,指向了一个历史版本(与行存储一样的结构,但是数据是不一样的)
如何工作呢?
- 如果行数据中的
trx_id
小于min_trx_id
,那么就可以读,修改行数据的事务已经提交了,所以对当前事务可见 - 如果行数据中的
trx_id
大于等于max_trx_id
,那么就不能读,因为这是在该事务之后创建的事务,所以对当前事务不可见 - 如果行数据中的
trx_id
小于max_trx_id
而大于等于min_trx_id
,那么需要查看是否在m_ids
中,在就不可见,不在就可见。
可重复读级别工作流程
启动事务就创建一个Read View
,整个事务期间都用这个Read View
,那么整个事务期间,读取的数据都跟事务启动一样了
读提交级别工作流程
每次读取数据时候,都生成一个新的Read View
,这样,并不能保证可重复读。
幻读问题
InnoDB
是怎么解决幻读问题呢?
- 针对快照读(
select
语句),通过MVCC - 针对当前都(
select for update
),使用next-key lock
解决