mysql事务实现是在存储引擎层,但并不是所有引擎都支持事务,比如myisam,也是innodb替代myisam的原因之一

事务特性

ACID四原则,一次是原子性、一致性、隔离性和持久性(Atomicity、Consistency、Isolation、Durability)
因为事务在存储引擎层实现,所以事务特性也是发生在引擎层。

1、原子性

2、一致性

3、隔离性

存储引擎要支持并发操作,所以多个事务之间就会产生一些数据冲突,一般有脏读、不可重复读和幻读(dirty read、no-repeatable read、phantom read),先说说这几个意思:

  • 脏读:事务A读到了事务B还未提交的数据。可能发生在读未提交隔离级别。
  • 不可重复读:因别的事务修改了数据,导致事务A前后读到的数据不一致。可能发生在读未提交、读提交隔离级别
  • 幻读:事务A先读数据,事务B再插入一些新行数据,事务A再去读数据,读到了新行,就像产生了幻觉。可能发生在读未提交、读提交、可重复读隔离级别。

隔离级别:

  • 读未提交:多个事务之间,同个事务可以读到别的事务未提交的数据
  • 读提交:多个事务之间,同个事务可以读到别的事务已提交的数据
  • 可重复读:多个事务之间,同个事务先后读到的是一致的数据
  • 串行化:多个事务之间,依次同步执行所有事务,不能并发。

4、持久性

事务隔离

1、事务隔离实现

在隔离实现上,会创建数据库视图来控制数据访问。不同隔离级别会在不同阶段产生视图,读取结果也就以最终的视图逻辑结果为准。

  • “读未提交”:没必要创建视图,直接读取表当前最新记录就好。
  • “读提交”:因为允许读取其他事物已提交的数据,此时表里是其他事物已提交修改的最新数据,所以只需要控制在sql执行时根据当前表数据创建视图即可。
  • “可重复读”:因为要保证同一个事物里不同的读取目标数据前后一致,所以要在事物开始时就要创建好视图,整个事务执行都围绕此视图进行。该视图是在整个库的快照中。
  • “串行化”:因为是串行执行事务,不能产生并发,要隔离事务,只能通过加锁方式,保证事务可串行执行。

多版本并发控制
假设字段status从 1 被按顺序改成了 2、3、4,每个修改都会写一条回滚日志(undo log),同时与数据一起写入回滚日志的还有事务id。在回滚日志里面就会有类似下面的记录。

当前值加回滚段,同一条记录在当前系统里就会同时存在多个版本(row),保证多个事务的数据隔离,这就是多版本并发控制(mvcc)
在可重复读隔离级别下,一个事务启动时保存的视图快照肯定是所有已提交事务的数据。

如上图,当前值是4,但不同时刻启动的事务产生不同的视图,比如read-view A的事务,该事务是把1更新成了2,所以undo log记录的是将2改成1。同理可推算视图B。所以事务A要再读取该字段时,就必须根据当前值status=4从undo log里依次往后比较trx_id,直到trx_id=A_trx_id对应的记录,然后计算出status=1。

  • 当系统里没有比当前回滚日志更早的read-view时,就会删除该回滚日志。
  • 当事务失败或rollback时就能通过undo log恢复当前记录的值。
  • 长事务意味着更多的undo log,因为undo log是跟数据字典(行记录)一起混合记录在ibdata的里,没区分开,所以即使回滚段不需要被删了,文件也不会变小,所以可能会很占用内存。
  • 长事务还可能会占用锁资源,可并发数支撑减少,以致拖跨整个库。