咱们知道innodb 支撑事务。那么事务其中一个功能是须要支持回滚。
事务中可能设计到增,删,改等操做。那么回滚如和实现呢?sql
undo log 就是记录这些用于回滚的信息。
那么MVCC 为何也是靠undo log来实现的呢?
也许你据说过聚簇索引每条记录有个隐藏字段叫row_id
,他的做用是若是不指定主键,它就变成了系统内部的自增主键。同时其实每条记录还有两个字段一个是trx_id
,一个是roll_pointer
.这个两个字段就是用来实现MVCC功能。shell
trx_id
: 修改当前记录的事务id。roll_pointer
:只向一个undo log。每一条undo log记录固然也有trx_id, 和roll_pointer字段。服务器
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`age` int(11) NOT NULL,
`addresss` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `index_age` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
INSERT student VALUES (1,'张一',1,'ssss'),(2,'张二',2,'ssss');
复制代码
聚簇索引内容相似于一下:spa
id | name | age | address | trx_id | roll_pointer |
---|---|---|---|---|---|
1 | 张一 | 1 | ssss | 10 | insert_undo_log 地址 |
2 | 张二 | 2 | ssss | 10 | insert_undo_log 地址 |
undo log相似于一下:设计
id | name | age | address | trx_id | roll_pointer | undo id |
---|---|---|---|---|---|---|
1 | 张一 | 1 | ssss | 10 | 空 | 0 |
2 | 张二 | 2 | ssss | 10 | 空 | 1 |
undo id 的在同一个事务中依次递增的。code
update set age=10 where id = 1; #更新语句一
update set age=20 where id = 1; #更新语句二
复制代码
id | name | age | address | trx_id | roll_pointer | undo id |
---|---|---|---|---|---|---|
1 | 张一 | 1 | ssss | 20 | 指向上一条insert log 地址 | 0 |
1 | 张一 | 10 | ssss | 21 | 上一条undo log 地址 | 0 |
几点说明:索引
信息结构要复杂的多
,会分更新主键,和不更新主键
的状况。这里不详细展开。在MYSQL 5.6 以后,能够为undo log 分配独立的表空间。
默认表空间的数量为2个,能够设置innodb_undo_tablespaces 来增长数量。
每一个表空间又被分为多个回滚段(rollback segment),回滚段的数量能够查看innodb_undo_logs。
每一个回滚段就存放了undo log 页。
若是undo log 对应的事务都已是执行完毕,或者回滚结束的。那么对应的undo log 空间就能够被回收了。
假设有一个长事务,迟迟未被提交,或回滚,那么undo log 会愈来愈大。严重的会直接致使服务器磁盘空间爆满。因此若是忽然服务器磁盘空间使用量快速上升,也能够查看下是否有长事务没有提交,致使undo log占用很大磁盘空间。事务
undo log 两大做用:innodb
保障事务的原子性
。事务中的全部更新语句,要么全被执行,要么全被回滚。经过将同一个trx_id 的undo log 就能够实现回滚同一事务的全部更新语句了。