网站名称需要注册吗,企业qq手机版,ui设计工资怎么样,网站搜索工具上一篇文章#xff0c;介绍了隔离级别#xff0c;MySQL默认是使用可重复读#xff0c;但是在可重复读的级别下#xff0c;可能会出现幻读#xff0c;也就是读取到另一个session添加的数据#xff0c;那么除了配合使用间隙锁的方式#xff0c;还使用了MVCC机制解决#…上一篇文章介绍了隔离级别MySQL默认是使用可重复读但是在可重复读的级别下可能会出现幻读也就是读取到另一个session添加的数据那么除了配合使用间隙锁的方式还使用了MVCC机制解决保证在可重复读的场景下同一个session读取的数据一致性。
mvcc机制
MVCC(Multi-Version Concurrency Control) 多版本并发控制机制对同一行数据的读和写操作默认不会加锁互斥保证隔离型提高性能而串行化隔离级别为了保证较高的隔离型是将所有操作通过互斥来实现的。
Mysql在读已提交和可重复读隔离级别下都实现了MVCC机制。
原理
其实undo日志链是指一行数据被多个事务依次修改过后每个事务修改完后mysql都会保留修改前的数据undo 回滚日志并且添加两个隐藏字段trx_id 和 roll_pointer 将undo日志链串联形成一个历史记录版本链。 通过数据快照的方式。关键核心是undo日志和readView
什么时候会生产trx-id ? 在begin transaction的时候并不会新建在执行到他们之后的第一个修改操作InnoDB表的语句的时候事务才真正启动向mysql申请事务idmysql内部是严格按照事务的启动顺序来分配事务id的。 一个案例 mysql CREATE TABLE t (id int(11) NOT NULL,k int(11) DEFAULT NULL,PRIMARY KEY (id)
) ENGINEInnoDB;
insert into t(id, k) values(1,1),(2,2);最终结果事务A读取的是1而事务B读取的是3。为什么是这样我们来分析一下。 假设在事务A开始的时候只有一个transaciton id 1, 那么事务A就是2事务B就是3事务C就是4.
事务A的试图数组就是[1,2] 事务B视图数组[1,2,3] , 事务C视图数组[1,2,3,4]; 当事务C进行修改kk1 就将id1的k 设置为2。但是接着事务B也加1操作此时事务B的1操作其实是当前读也就是获取最新的数据k2, 在k2的基础上1 操作那么k3。所以事务B的K值事3。但是事务A的视图数组[1,2] 查询undo日志链发现 【34】都查看不了所以k1
对比规则 如果 row 的 trx_id 落在绿色部分( trx_idmin_id )表示这个版本是已提交的事务生成的这个数据是可见的; 如果 row 的 trx_id 落在红色部分( trx_idmax_id )表示这个版本是由将来启动的事务生成的是不可见的(若 row 的 trx_id 就是当前自己的事务是可见的); 如果 row 的 trx_id 落在黄色部分(min_id trx_id max_id)那就包括两种情况 a. 若 row 的 trx_id 在视图数组中表示这个版本是由还没提交的事务生成的不可见(若 row 的 trx_id 就是当前自己的事务是可见的); b. 若 row 的 trx_id 不在视图数组中表示这个版本是已经提交了的事务生成的可见
一个简易的版本就是
版本未提交不可见版本已提交但是是在视图创建后提交的不可见版本已提交而且是在视图创建前提交的可见。
MVCC机制的实现就是通过read-view机制与undo版本链比对机制使得不同的事务会根据数据版本链对比规则读取 同一条数据在版本链上的不同版本数据。
不同的读操作
select * from table where ?;
select * from table where ? lock in share mode; # 加读锁 select * from table where ? for update;# 加写锁
insert into table values (...);# 加写锁
update table set ? where ?;# 加写锁
delete from table where ?;# 加写锁
# 所有以上的语句都属于当前读读取记录的最新版本。并且读取之后还需要保证其他并发 事务不能修改当前记录对读取记录加锁。
# 其中除了第一条语句对读取记录加读锁外其他的操作都加的是写锁。那么思考一个逻辑。如果一个事务A 对id1更新操作的时候还没有提交那么事务B也对id2更新操作会出现什么情况
答案就是会阻塞事务B必须等事务A执行完毕。 bufferpool缓存 在我们更新一条SQL数据的时候大概流程如下 1.构建连接、查询缓存、分析器、优化器、执行器 2.在执行器的时候
如果buffer pool有对应的页数据直接获取否则从磁盘加载对应的id1的数据 namezhuge。将name‘zhuge’ 进行写入undo日志文件中主要方式如果事务进行回滚的话可以直接恢复数据更新内存中的buffer pool的数据 name‘zhuge 666’写入redo log日志。准备阶段。 系统宕机用于恢复数据 重做写入bin log日志然后提交事务。
我们来思考下为什么需要设计一套这么复杂的因为主要是对于磁盘的操作是随机IO性能不高可以通过写入LOG文件提升性能。先更新到BufferPool中然后顺序写日志文件。也可以保证各种异常情况下数据的一致性。
几个小问题 1.脏页刷盘的时机大概四种 a.redolog满了 binnodl buffer满了 c:myg正常关闭 d.mysql空闲 2.如果数据库突然奔溃了没刷盘的数据是不是就丟了不会redolog防崩溃 3.如果redo.log没写入磁盘这时候这部分事务是不是数据就丢了redolog buffer 里的数据丢了怎么办redolog buffer记录的是 事务prepare阶段数据未提交 丢了无所谓 4.如果redolog在刷盘的时候断电呢。
总结
MySQL的事务是如何保证的我们用了两篇文章进行详细描述通过ACID其中AID是为了保证C。 隔离性MVCC原理、原子性innodb 事务二阶段提交、D持久性事务提交后的数据落盘。以及通过相关的锁机制来保证。