Transaction

参考:小林 coding

事务的特性

atomicity: undo log

consistency: 由其他三个特性实现.事务在执行前后,数据库从一个一致性状态转变到另一个一致性状态。

isolation: MVCC/lock.一个事物的执行不影响其它事务的执行

duration: redo log 一旦事务被提交,它对数据库的改变就是永久性的,即使在系统故障或崩溃后也能够保持。

启动事务

begin/start transaction表示开始事务,只有在执行这条命令后,执行了第一条 select 语句,事务才真正启动。
start transaction with consistent snapshot 表示立即启动事务

事务的隔离级别

可能出现的问题:脏读、不可重复读、幻读
脏读:事务 A 读取了事务 B 还未提交的数据。如果事务 B 回滚,则导致事务 A 读取了错误的数据。
不可重复读:在一个事务中,前后两次读同一个数据,读到的值不一样。比如事务 A 第一次读到a为1,然后事务B把a修改为2,提交了这个修改,事务A再去读a发现它为b.
幻读:在一个事务中,前后两次查询符合某个条件的记录数量,发现数量有变化。使得数据库并发时性能很差。

读未提交:性能最高、一致性最差,几乎不会在实际生产环境中使用。 无需锁无需 MVCC,直接读取最新的数据。 读已提交:行级锁/MVCC
可重复读:InnoDB的默认隔离级别。
串行化:读操作会对读取的数据加共享锁,写操作会对修改的数据加排他锁。

MVCC

参考视频

Alt text undo log中有两个隐藏列,trx_id(事务编号) 和 roll_pointer(指向该记录的上一个版本)。

m_ids是一个列表,记录了当前所有活跃的事务 Id(已经开始,未提交)
min_trx_id是最小活跃事务 Id
max_trx_id是最大活跃事务 Id(当前事务)+1
createor_trx_id是创建这个 read view 的事务 Id

select的时候,对任意一行(任意一条事务链),都只有一个版本可以被选中

如果是读已提交隔离级别,事务每次读数据的时候,会生成一个快照。
如果是可重复读隔离级别,在事务开始的时候,生成一个快照。

在事务链中,从上往下,读取它们的事务 id

  1. 拿它与creator_trx_id比较,如果相等,说明当前事务就是创建者,他可以访问自己的版本。如果不是,去下一步。
  2. 和min_trx_id比较,如果这个事务,它小于当前活跃的最小事务id, 说明它在这个快照生成之前已经提交,所以这个事务的版本是可以被select到的。如果不是,下一步。
  3. 和max_trx_id比较,如果大于,说明这个事务在快照生成之后才开启,所以不能被select到。直接跳到下一条事务。如果不是,下一步
  4. 如果在min_trx_id和max_trx_id之间,同时它不在活跃事务链表中,则它可以被 select 到。如果不是,则跳到下一条事务。

解决幻读

InnoDB的可重复读隔离级别很大程度上能解决幻读问题。

针对快照读,是在事务开启的时候生成快照。所以事务开启之后,如果有新的数据加进来了,查询的时候也查不到这条数据。

事务的传播

若方法 A 开启了事务,而方法 A 调用了方法 B,方法 B 的调用也是需要事务的

PROPAGATION_REQUIRED:方法 B 可以加入方法 A 的事务。如果方法 A 没有开启事务,方法 B 自己创建一个事务。

PROPAGATION_REQUIRES_NEW:不管有没有事务,都新建一个事务。