查网站开发者,58同城网招聘找工作下载安装,hao123网站源码制作2015最新仿,前端和后端哪个常熬夜多版本并发控制是一种用于支持并发事务的数据库管理系统技术#xff0c;它允许多个事务同时访问数据库#xff0c;而不会相互干扰或导致数据不一致。MVCC通过在数据库中维护不同版本的数据来实现这一目标#xff0c;从而允许每个事务看到一致的数据库快照。
并发导致的问题…多版本并发控制是一种用于支持并发事务的数据库管理系统技术它允许多个事务同时访问数据库而不会相互干扰或导致数据不一致。MVCC通过在数据库中维护不同版本的数据来实现这一目标从而允许每个事务看到一致的数据库快照。
并发导致的问题
数据库并发是指在同一时间内多个事务同时对数据库进行读取和写入操作的能力。以下是三种常见的数据库并发场景
读-读并发 多个事务同时对数据库进行读取操作彼此之间不涉及写入操作。读-写并发 多个事务同时进行读取和写入操作存在线程安全问题会产生脏读、不可重复读、幻读。写-写并发 多个事务同时进行写入操作可能涉及操作同一条数据导致数据丢失事物 1 事物 2 同时更新一条记录时事物 1 提交事物 2 也提交事物 1 回滚后导致覆盖掉了事物 2 的更新。
最早的数据库系统只有读读之间可以并发读写写读写写都要阻塞。引入多版本之后只有写写之间相互阻塞MySQL 自动对涉及的数据行加上即排他锁其他三种操作都可以并行这样大幅度提高了InnoDB的并发度。
实现 MVCC
InnoDB 会向数据库中的每行记录增加三个字段 DB_ROW_ID隐藏的自增 ID主键6字节如果有主键则不会包含该列如果没有主键会根据DB_ROW_ID 产生一个聚餐索引。 DB_TRX_ID事务ID6字节记录插入或 最后一次更新这条记录的事务 IDMySQL InnoDB 里面每个事务都会有一个唯一事务 ID它在事务开始的时候会跟 InnoDB 的事务系统申请的并且严格按照顺序递增的。 DB_ROLL_PTR回滚指针7字节指向上个版本数据在 undo log 里的位置。
版本链
新 insert 的数据没有 undo log**DB_ROLL_PTR **字段为空。 当要 update 数据的时候会先创建 undo log以及指向该 undo log 的回滚指针 roll_ptr并且会将 roll_ptr 更新到 **DB_ROLL_PTR **字段中更新数据的 DB_TRX_ID 属性为当前的事务 ID 。当某条数据被多次修改时该数据会存在多个版本通过 DB_ROLL_PTR 链接形成一个类似版本链的概念。
当前读和快照读
当前读Current Read 当前读是一种读取操作事务在执行读取时会读取数据库的当前状态包括其他事务已经提交的变更。当前读允许事务读取最新的实时数据但也可能受到其他并发事务的影响可能发生不可重复读等问题。常见的 update/insert/delete、还有 select … for update、select … lock in share mode 都是当前读。 快照读Snapshot Read 快照读是一种读取操作事务在执行读取时会获得一个数据库的快照或一个特定时间点的数据视图。也就是 MVCC 生成的 ReadView。在整个事务执行期间这个数据视图保持一致即事务看到的是事务开始时数据库的快照不受其他事务的影响。用于普通的 select 的语句。
一致性视图ReadView
当隔离级别为 RR 时每开启一个事务数据库系统会给这个事务分配一个事务 ID这个 ID 是自增的所以事物 ID 越大事物越新当这个事务执行 select 语句的时候会生成一个当前时间点的事务快照读视图ReadView ReadView 包含几个属性 m_ids 创建当前 ReadView 时系统活跃事务 id 升序的列表即还未提交的事物 id 列表。 m_low_limit_id 不可见范围的最小lowid 创建当前 ReadView 时将要分给下一个事物的 id也就是当前系统最大事务版本号1。 m_up_limit_id可见范围的最大upid 创建当前ReadView 时系统正处于活跃事务最小版本号 m_creator_trx_id 创建当前ReadView的事务 id 代码位置 mysql-8.1.0\storage\innobase\read\read0read.cc
可见性判断
当某个事务执行快照读的时候会创建一个 ReadView 读视图并且用这个 ReadView 判断当前事务能够看到哪个版本的数据。可能是当前最新的数据也有可能是该行数据的 undo log版本链 里面的某个版本的数据。一个事务启动后判断某个版本的数据能否被该事务访问判断流程如下 1、 如果被访问版本的 DB_TRX_ID 与 该事务创建的 ReadView 中的 m_creator_trx_id 值相同说明就是当前这个事务在访问它自己修改过的数据。 2、 如果被访问版本的 DB_TRX_ID ReadView 中的 m_up_limit_id低水位表明被访问版本的事务在当前事务生成 ReadView 前已经提交所以该版本可以被当前事务访问。 3、 如果被访问版本的 DB_TRX_ID ReadView 中的 m_low_limit_id高水位表明被访问版本的事务在当前事务生成 ReadView 后才开启所以该版本不可以被当前事务访问。 4、 m_low_limit_id DB_TRX_ID m_up_limit_id 之间这种情况就说明这个数据有可能是在当前事务开始的时候还没有提交的可以分情况判断
如果 DB_TRX_ID 不在 m_ids 列表中说明创建 ReadView 时生成该版本的事务已经被提交该版本可以被访问。如果 DB_TRX_ID 在 m_ids 中则说明read view产生的时候数据还没有提交但是如果 DB_TRX_ID creator_trx_id 那么说明这个数据就是当前事务自己生成的该版本可以被访问。如果 DB_TRX_ID 在m_ids 中且 DB_TRX_ID 不等于creator_trx_id那就说明read view产生的时候数据还没有提交又不是自己生成的所以这种情况下该版本不能被访问。
以上三种情况是通过二分法进行查找判断的。 5、如果该版本的条件都不满足ReadView 的条件时则通过当前版本的 DB_ROLL_PTR 找到上一个版本再来和ReadView 条件匹配直到找到一条满足条件的历史数据找不到则返回空结果。
RC/RR级别快照读
RC/RR 级别生成 ReadView 的时机是不同的
在 RR 级别下的某个事务对某条记录进行的第一次 select 会创建一个快照 Read View此后在调用快照读的时候使用的还是同一个ReadView所以只要当前事务在其他事务提交更新之前使用过快照读那么之后的快照读使用的都是同一个Read View所以对之后的修改不可见.在 RC 级别下事务中每次 select 都会生成一个快照和 ReadView这就是我们在 RC 级别下的事务中可以看到别的事务提交更新的原因。
总之在 RC 隔离级别下每次快照读都会生成最新的 ReadView而在 RR 级别下则是同一个事务中的第一个快照读才会创建ReadView之后的快照读获取的都是同一个 ReadView。所以说 RR 在 RC 的基础上通过生成 Read View 的时机不同从而解决了不可重复读的问题。
数据删除和purge 线程
而对于删除其实就是一种特殊的更新InnoDB 在 info_bits 中用一个标记位 delete_flag 标识是否删除并不真正将过时的记录删除。当我们在进行判断时会检查下 delete_flag 是否被标记如果是会有专门的 purge 线程来清理。
什么是记录锁什么是间隙锁什么是 Next-Key Locks
记录锁、间隙锁也称为范围锁、以及临键锁是三种不同类型的锁用于管理并发事务的访问InnoDB 的锁是加上在索引上的。
记录锁Record Locks
这种锁直接应用在数据库表中的记录行上。当一个事务请求对某一行的记录进行写操作时系统可能会给该记录加上记录锁防止其他事务同时修改同一行。这确保了在给定时间只有一个事务能够修改该记录从而维护数据的一致性。
间隙锁Gap Locks
间隙锁锁定的是两个记录之间的间隙左开右开的区间。这主要用于防止其他事务在间隙中插入新的记录从而确保范围查询的一致性其它事务在这个间隙做删除操作也会被锁阻塞的。如果一个事务执行范围查询操作并使用了间隙锁它将锁定查询范围内的所有记录以及这些记录之间的空隙防止其他事务在这个范围内插入新的记录。间隙锁是可重复读RR隔离级别下特有的。 比如语句select * from user where age1 and age10 for update将会锁住age在(1,10)的范围区间此时其他事务对该区间的操作都会被阻塞
临键锁Next-Key Locks
是通过算法将记录锁和间隙锁组合 锁住的是左开右闭的区间。
MVCC 解决幻读了吗
在 快照读普通 select 语句的时候是通过 MVCC 方式解决了幻读因为可重复读隔离级别下在执行第一个查询语句后会创建一个 Read View后续的查询语句利用这个 Read View通过这个 Read View 就可以在 undo log 版本链找到事务开始时的数据所以事务过程中每次查询的数据都是一样的即使中途有其他事务插入了新纪录是查询不出来这条数据的所以就很好了避免幻读问题。 在 当前读select … lock in share mode、select … for update、insert、 update、 delete 等语句时这些语句执行前都会查询最新版本的数据是通过 Next-Key Locks记录锁间隙锁只在方式解决了幻读因为当执行这些语句的时候会自动加上 Next-Key Locks如果有其他事务在 Next-Key Locks 锁范围内插入了一条记录那么这个插入语句就会被阻塞无法成功插入所以就很好了避免幻读问题。 如果事务中都使用快照读那么就不会产生幻读现象但是如果快照读和当前读混用就会产生幻读。
临键锁一定解决了幻读问题吗
按照 MySQL 官方的说法即使在可重复读的情况下幻读仍然是可能的。官方说法https://bugs.mysql.com/bug.php?id63870所以有更高的隔离级别出现。