MySQL8.0开始支持DDL原子语句,它指的是将数据字典更新、存储引擎操作和与DDL操作相关的二进制日志写入合并为一个单一的原子操作。即使在这些过程中,服务器停止,DDL原子操作包含的几个过程要么一起提交,要么一起回滚。
DDL隐含其他事务结束
原子DDL并不是事务性的DDL,跟一般的DDL一样,它会结束当前回话的其他事务。这点以前没有注意过,看个例子:
start transaction;
insert into t_person values(2,'Hello','上海');
create table t (id int);
rollback;
create table 正常执行隐含了commit,所以后面的rollback没有成功。再看个DDL失败的例子:
start transaction;
insert into t_person values(3,'Hi','上海');
drop table t_not_exists;
rollback;
虽然t_not_exists不存在,drop 语句会报错,但是DDL隐含了对其他事务的提交,所以insert 语句成功提交了。
支持的原子DDL语句
MySQL8.0支持的原子DDL语句,主要包含两类:
- Table DLL:数据库、表空间、表和索引的CREATE、ALTER和DROP语句,以及TRUNCATE TABLE语句
- Non-Table DLL:存储程序、触发器、视图以及函数的CREATE、DROP 、ALTER语句;以及用户和角色相关的 CREATE、ALTER、 DROP、 GRANT和REVOKE。
几个需要注意的事项:
- 目前支持原子DDL的只有InnoDB引擎
- DROP TABLE, 可以同时DROP多个表,如果这些表都是InnoDB引擎的话,那么要不一起删除或者一起回滚。如何含有不支持原子DDL存储引擎的表,那么这些不支持的表,会先一步单独处理;
- 原子DDL支持 CREATE TABLE … SELECT,前提是BINLOG的格式是ROW。当作为原子操作执行的时候,插入数据会在表上加上元数据锁,这会阻止对表的并发访问。
- 帐户管理语句要么对所有指定的用户成功,要么在发生错误时回滚并没有影响。不允许部分执行
InnoDB引擎如何支持原子DDL
为了支持DDL操作的重做和回滚,InnoDB将DDL日志写入mysql.innodb_ddl_log表,这是一个隐藏的数据字典表,位于mysql.ibd数据字典表空间中。InnoDB将DDL的执行分为几个阶段:
- Prepare:创建所需的对象,并将DDL日志写到mysql.innodb_ddl_log表中。DDL日志定义了如何向前滚动和向后滚动DDL操作。
- Perform:执行DDL操作
- Commit:更新数据字典并提交数据字典事务。
- Post-DDL:重放并从mysql.innodb_ddl_log表中删除DDL日志。为了确保可以安全地进行回滚而不引入不一致,在这个最后阶段进行文件操作, 比如重命名或删除文件;这个阶段也从mysql.innodb_dynamic_metadata数据字典表中删除动态元数据(对于DROP TABLE或重建表等操作)