时间:2021-07-01 10:21:17 帮助过:13人阅读
start transaction;
insert into tb(name) values('shenjian') ;
insert into tb(name) values('zhangshan');
insert into tb(name) values('lisi');
commit;
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | undefinded |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
对select 的影响:
innodb 只会去查找版本好小于或等于(早于)当前事务ID的数据行,这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的
行的删除版本要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除.
只有1、2同时满足的记录,才能返回作为查询结果.
例2:delete操作
InnoDB会为删除的每一行保存当前系统的版本号(事务的ID)作为删除标识.
看下面的具体例子分析:
第二个事务,ID为2;
start transaction;
select * from tb; //(第一步操作:1)
select * from tb; //(第二部操作:2)
commit;
假设:在这个事务的的执行过程中到第一步操作:1 的时候。
又开启了一个新事务(ID 为3)向表中执行Insert 操作插入数据
start transaction;
insert into tb(name) values('wangwu') ;
commit;
此时的表中数据为:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | undefinded |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
4 | wangwu | 3 | undefinded |
然后刚才事务2,中的第二步:2 开始执行,引文id=4的数据的创建时间(事务ID为3),执行当前事务的ID为2,而InnoDB只会查找事务ID小于等于当前事务ID的数据行,所以id=4的数据行并不会在执行事务2中的第二步:2 中被检索出来,在事务2中的两条select 语句检索出来的数据都只会下表:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | undefinded |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
再假设:假设在执行事务ID为2的过程中,刚执行到了第一步:1,假设事务执行完事务3后,接着又执行了事务4;
事务4:
st art transaction;
delete from tb where id=1;
commit;
此时数据库中的表为:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | 4 |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
4 | wangwu | 3 | undefinded |
接着执行事务ID为2的第二步:2,根据select 检索条件可以知道,它会检索创建时间(创建事务的ID)小于当前事务ID的行和删除时间(删除事务的ID)大于当前事务的行,而id=4的行上面已经说过,而id=1的行由于删除时间(删除事务的ID)大于当前事务的ID,所以事务2的第二步:2 select * from tb 会把id=1的数据检索出来.所以,事务2中的两条select 语句检索出来的数据都如下:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | 4 |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
update:
InnoDB执行UPDATE,实际上是新插入了一行记录,并保存其创建时间为当前事务的ID,同时保存当前事务ID到要UPDATE的行的删除时间.
再再假设:
假设在执行完事务2的第一步:1 后又执行,其它用户执行了事务3,4,这时,又有一个用户对这张表执行了UPDATE操作:
第5个事务:
start transaction;
update tb set name='xxx' where id=2;
commit;
按照update的更新原则:会生成新的一行,并在原来要修改的列的删除时间列上添加本事务ID,得到表如下:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | 4 |
2 | zhangsan | 1 | 5 |
3 | lisi | 1 | undefinded |
4 | wangwu | 3 | undefinded |
2 | xxx | 5 | undefinded |
继续执行事务2第二步:2,根据select 语句的检索条件(创建时间事务ID小于自己查询事务ID的,和删除时间事务ID大于自身的查询事务ID),得到下表:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | 4 |
2 | zhangsan | 1 | 5 |
3 | lisi | 1 | undefinded |
并得不到上上个表的ID=4的第四行(因为创建事务ID=3 > 查询事务ID=2) 和第五行Update 事务创建的ID=2 的更新数据(因为 创建他的Update 事务ID=5 > 查询事务ID=2)
Mysql 中的MVCC原理,undo日志的依赖
标签:prim mvc 大于 初始 name targe 一起 日志 detail