MySQL事务总结
事务的特性ACID
InnoDB 引擎支持事务,MyISAM 引擎不支持事务
事务的四个特性:
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
- 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
实现:
- 原子性:通过 undolog 来实现。
- 持久性:通过 binlog、redolog 来实现。
- 隔离性:通过(读写锁+MVCC)来实现。
- 一致性:MySQL 通过原子性、持久性、隔离性最终实现数据一致性。
对 MySQL 来说,逻辑备份日志(binlog)、重做日志(redolog)、回滚日志(undolog)、锁技术 + MVCC 就是 MySQL 实现事务的基础。
并发事务问题
问题 | 描述 |
---|---|
脏读 | 一个事务读到另外一个事务还没有提交的数据。 |
不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。 |
幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了”幻影”。 |
事务的隔离级别:
- 读未提交:一个事务还没提交时,它做的变更就能被其他事务看到;(脏读,不可重复读,幻读)
- 读提交:一个事务提交之后,它做的变更才能被其他事务看到;(不可重复读,幻读)
- 可重复读:指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,InnoDB 引擎的默认隔离级别,(幻读)
- 串行化:会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行;
幻读解决:
- 针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好的避免幻读问题。
- 针对当前读(select ... for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select ... for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。
隔离级别的实现方式:
- 读未提交:直接读
- 读已提交:每个语句都生成一个ReadView
- 可重复读:启动事务生成一个ReadView,整个事务期间都用
- 串行化:读写锁
MVCC工作原理
多版本并发控制(MVCC):这是InnoDB存储引擎特有的一种机制,它可以在不加锁的情况下创建数据在某一时间点的快照。在读取数据时,MVCC会返回该时间点的数据版本,即使该数据后来被其他事务修改。这样,每个事务都有自己的数据视图,彼此之间不会互相影响,实现了隔离性。
四个字段
聚簇索引两个隐藏列:
三种情况:
- 如果记录的
trx_id
值小于 Read View 中的min_trx_id
值,表示这个版本的记录是在创建 Read View 前已经提交的事务生成的,所以该版本的记录对当前事务可见。 - 如果记录的
trx_id
值大于等于 Read View 中的max_trx_id
值,表示这个版本的记录是在创建 Read View 后才启动的事务生成的,所以该版本的记录对当前事务不可见。 - 如果记录的
trx_id
值在 Read View 的min_trx_id
和max_trx_id
之间,需要判断trx_id
是否在m_ids
列表中:- 如果记录的
trx_id
在m_ids
列表中,表示生成该版本记录的活跃事务依然活跃着(还没提交事务),所以该版本的记录对当前事务不可见。 - 如果记录的
trx_id
不在m_ids
列表中,表示生成该版本记录的活跃事务已经被提交,所以该版本的记录对当前事务可见。
- 如果记录的
这种通过「版本链」来控制并发事务访问同一个记录时的行为就叫 MVCC(多版本并发控制)。