![](https://img.haomeiwen.com/i8544344/28e4cd938e09bf61.jpg)
情景:将一组数据写入数据库的四张表a,b,c,d(期间会进行建表操作)中,要求这一操作具有原子性。
代码逻辑:
(1) 开启事务。
(2) 对数据库进行读写或改变数据对象行为(执行DDL或者DML)。
(3) 异常处理,如果捕获到异常,则对事务进行回滚,如果没有异常,则进行提交。
测试,出现了两种情况:
(1) 捕获到异常后回滚成功。(达到目的)
(2) 捕获到异常后回滚失败。(失败状态)
分析:代码逻辑没有多大问题,经过查阅资料,原来是DDL的隐式提交造成的。DML一旦出现异常,是可以进行正常的回滚的,但是只要一执行到DDL,不管这句DDL有没有报异常,都会进行一次commit,这就造成了这样的情形,成功表现为该操作具有原子性,但是一旦DDL出现异常,会把前面所执行的DML全部提交,所以,就使得捕获到异常后回滚失败,导致操作失去原子性。以下对该过程进行验证。
DDL,DML和DCL简介
1. DDL: 数据定义语言,用于定义和管理 SQL 数据库中的所有对象的语言,这种对象包括数据库本身,以及数据库对象,如表、视图等等,DDL对这些对象和属性的管理和定义具体表现在create、drop和alter上。
DDL的主要语句(操作)
(1) create语句:可以创建数据库和数据库的一些对象。
(2) drop语句:可以删除数据表、索引、触发程序、条件约束以及数据表的权限等。
(3) alter语句:修改数据表定义及属性。
2. DML:数据操作语言,SQL中处理数据等操作统称为数据操纵语言,用于操作数据库对象中包含的数据,也就是说操作的单位是记录。
DML的主要语句(操作)
(1) insert语句 :向数据表张插入一条记录。
(2) delete语句:删除数据表中的一条或多条记录,也可以删除数据表中的所有记录,但是,它的操作对象仍是记录。
(3) update语句:用于修改已存在表中的记录的内容。
3. DCL:数据控制语言,用来授予或回收访问数据库的某种特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监视等。
DCL的主要语句(操作)
(1) grant语句:允许对象的创建者给某用户或某组或所有用户(PUBLIC)某些特定的权限。
(2) revoke语句:可以废除某用户或某组或所有用户访问权限
DDL语句的隐式提交
1.首先验证DML语句可以进行正常的事务回滚,这里以表test为实验对象,下面为该表的结构
![](https://img.haomeiwen.com/i8544344/2c1a0ed416393ddf.png)
这张表很简单,只有一个id字段。
1. 开启事务。
![](https://img.haomeiwen.com/i8544344/95bed5b5bc82a0f7.png)
2. 向test表写入1。
![](https://img.haomeiwen.com/i8544344/df51fff8a03ba4f2.png)
3. 回滚事务并并查看test表。
![](https://img.haomeiwen.com/i8544344/f062ea955b5bce31.png)
由结果可以看到,test表中的id值为空,这说明事务回滚成功。
删除上面写入的1,接下来为验证DDL的隐式提交。
1. 开启事务。
2. 向test表写入2。
![](https://img.haomeiwen.com/i8544344/2c25965dfcd29c2a.png)
3. 创建数据表test2。(忽略建表的时长...)
![](https://img.haomeiwen.com/i8544344/43c9fa43080491d5.png)
4.回滚事务并查看test表的数据。
![](https://img.haomeiwen.com/i8544344/8879fce8d3286acc.png)
由上面的结果可以知道,id=2在test表中仍然存在,说明回滚失败了。
分析:查看binlog (可以看我的另一篇binlog的学习总结MySQL的binlog日志 - 简书)
![](https://img.haomeiwen.com/i8544344/3e49418901fa0027.png)
执行这两条语句,是最后才rollback的,期间并没有做任何的commit,但是在执行完第一条语句后,从binlog中可以看到,又执行了一次commit,这是为什么呢,原因就是执行了后面的DDL语句,我们向test表写入id=2后又创建了一张test2表,就是这条创建语句,也就是DDL,会先commit一次,然后再执行,最后再commit。所以,就出现了在执行完第一条语句后commit了一次。也就是说,后面的rollback针对的是一个空事务,因此看到的就是回滚事务失败,其实并不是回滚失败,而是DDL不管成功与否,它都会先commit一次,只不过在出现异常时就会导致该操作的非原子性。
结论:DDL操作是隐性提交的!不能rollback,当执行到DDL语句时,会隐式的将当前会话的事务进行一次“commit”操作!
补充:为什么要在DDL上进行自动commit?TOM在asktom上给出了如下回答
Tom说:
a user that gets blocked on the "do the ddl" inside the savepoint is blocked on the transaction -- not the "subtransaction". Hence it would block people on the data dictionary -- a place we cannotafford to get jammed up.The data dictionary is "special" -- it drives the rest of the system. If portions of it get lockedup for extended periods of time -- it could be deadly.
DDL操作也就是数据定义语言,对表的结构进行修改,这个修改其实就是对数据字典中表的定义进行了修改。DDL操作发生了阻塞,那么”阻塞“这个动作其实是发生在了数据字典表上,在数据字典上发生严重的阻塞可不是一个小问题,数据字典和整个数据库相关连着,在数据字典上的长期阻塞可能会造成严重的问题。因此,在每个DDL执行后自动commit,提高数据库的整天性能。
网友评论