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
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
- 拿它与creator_trx_id比较,如果相等,说明当前事务就是创建者,他可以访问自己的版本。如果不是,去下一步。
- 和min_trx_id比较,如果这个事务,它小于当前活跃的最小事务id, 说明它在这个快照生成之前已经提交,所以这个事务的版本是可以被select到的。如果不是,下一步。
- 和max_trx_id比较,如果大于,说明这个事务在快照生成之后才开启,所以不能被select到。直接跳到下一条事务。如果不是,下一步
- 如果在min_trx_id和max_trx_id之间,同时它不在活跃事务链表中,则它可以被 select 到。如果不是,则跳到下一条事务。
解决幻读
InnoDB的可重复读隔离级别很大程度上能解决幻读问题。
针对快照读,是在事务开启的时候生成快照。所以事务开启之后,如果有新的数据加进来了,查询的时候也查不到这条数据。
事务的传播
若方法 A 开启了事务,而方法 A 调用了方法 B,方法 B 的调用也是需要事务的
PROPAGATION_REQUIRED:方法 B 可以加入方法 A 的事务。如果方法 A 没有开启事务,方法 B 自己创建一个事务。
PROPAGATION_REQUIRES_NEW:不管有没有事务,都新建一个事务。