事务并发执行会遇到什么问题
脏读:事务 A 读取到了事务 B 修改了但是没有提交的数据。 不可重复读: 事务 A 读取到别的事务已经提交的修改过的值,其他事务每次修改并提交,事务 A 读取的值都是最新的。 幻读: 事务 A 通过一些条件,查到的数据原本是 0 条,此时事务 B 新增了符合事务 A 查询条件的数据。事务 A 再次查询会发现和上次查询的结果不一致。
SQL 标准,事务的隔离级别
- RU(读未提交): 最低的隔离级别,可能发生
脏读
、不可重复读
、幻读
的问题 - RC(读已提交): 可能会发生
不可重复读
、幻读
的问题 - RR(可重复度): 可能会发生
幻读
的问题。(Mysql 在 RR 的隔离级别下,是可以禁止幻读问题发生的) - SER(串行化): 不会发生任何问题。
什么是 MVCC
针对
一条 Mysql数据
的 git 版本链路跟踪信息。
针对一行数据, 在聚簇索引记录中, 新增两个必要的隐藏列 (Row_ID
并不是必要的,我们创建的表中有主键,或者非 null 的 Unique 键的时候,都不会包含 row_id
列)
trx_id
: 事务 ID: 每次一个事务对某条聚簇索引记录进行变动的时候, 都会把这个事务的事务 ID 记录下来roll_prointer
: 旧版本的指针 ID, 把旧数据写入到undolog
中通过这个指针, 来找这个记录被修改之前的数据信息. (用来做事务的回滚)
什么是读视图 (ReadView)
针对 RC 和 RR 级别, 需要保证每次的读取都能读取到已经提交的事务修改过的记录. 人话: 事务 A 每次的读取, 都能读取到相对最新的数据. 保证了数据的版本链中, 那个版本的数据对当前事务是可见的.
m_ids
:表示在生成ReadView
时当前系统中活跃的读写事务的事务 ID 列表min_trx_id
: 表示在生成ReadView
时,当前系统中 活跃的 读写事务中最小的事务 ID,也就是m_ids
里的最小值max_trx_id
: 表示在生成ReadView
时,系统中应该分配给下一个事务的 ID 值.creator_trx_id
: 表示在生成ReadView
时的事务 ID如果被访问版本的事务 ID,与当前读视图的
creator_trx_id
一样,则意味着当前事务在访问它自己修改过的记录,所以这个版本可以被当前事务访问如果被访问版本的事务 ID,小于
min_trx_id
就说明这个读视图在这个事务执行完成后才生成,所以可见如果被访问版本的事务 ID,大于
max_trx_id
就说明这个读视图在这个事务没有执行完成之前就生成了, 所以不可见如果被访问版本的事务 ID, 在
min_trx_id
~max_trx_id
之间, 则需要判断这个事务 ID 在不在m_ids
中, 如果在, 说明这个事务还在活跃, 则不可见, 如果不在则说明可见.
针对 RC 级别: 每一次读取数据的时候, 都会生成一个读视图 针对 RR 级别: 只有第一次读取数据的时候, 会生成一个读视图
对于使用 InnoDB
存储引擎的表来说,它的聚簇索引记录中都包含两个必要的隐藏列(row_id
并不是必要的,我们创建的表中有主键或者非 NULL 的 UNIQUE 键时都不会包含 row_id
列):
- Trx_id : 事务 Id, 每次一个事务对某条聚簇索引记录进行改动时,都会把该事务的
事务id
赋值给trx_id
隐藏列。 - roll_pointer: 版本链路指针, 修改之后, 会把旧版本的数据写到
undolog
中 ,这里记录的可以理解成是undolog
的数据指针