事务特性

  • 原子性:要么全完成,要么全不完成
  • 一致性:事务前后,数据满足完整性约束
  • 隔离性:多个并发事务之间不干扰
  • 持久性:事务结束后,对数据修改是持久的

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进行事务的基础结构,它结构如下:

img

  • 行存储结构中就有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解决