DDL 语句总是给你一个隐式提交,还是你能得到一个隐式回滚?

Posted

技术标签:

【中文标题】DDL 语句总是给你一个隐式提交,还是你能得到一个隐式回滚?【英文标题】:Do DDL statements always give you an implicit commit, or can you get an implicit rollback? 【发布时间】:2009-04-08 15:49:22 【问题描述】:

如果您在事务进行到一半并执行 DDL 语句(例如截断表),则事务会提交。

我想知道这是否总是如此并且根据定义,或者是否有隐藏在某处的设置回滚事务而不是提交。

谢谢。

编辑以澄清...

我不希望在截断后回滚。我只是想确认已经执行的语句绝对总是会在 DDL 之前提交。只是想确保没有人可以设置破坏我的代码的系统属性。

我了解在 DDL 之前和之后提交的必要性,但从概念上讲,我认为可以通过在 DDL 之前回滚和之后提交来实现相同的一致性要求

【问题讨论】:

【参考方案1】:

不,它会一直提交。

如果要回滚,则必须在 DDL 之前进行。

如果您想将 DDL 与现有事务隔离,则必须在其自己的单独事务中执行它。

【讨论】:

嗨,我可以知道“在自己的单独事务中执行 DDL”是什么意思吗?我认为您的回答可以帮助我解决我的难题。如果你能在这里检查我的问题,你会很好:superuser.com/questions/1450028/… @Amir,我的意思是,如果您在脚本中间有一个 ddl,那么无论您是否愿意,该脚本将始终在该点提交。如果您想在不提交任何其他待处理操作的情况下执行 DDL,则需要在任何其他脚本之外执行此操作。【参考方案2】:

从技术上讲,DDL 在执行之前和之后执行提交。

是的,来自 Cookie 的相同链接,但这是同一问题的不同方面。重要的是要理解它不仅仅是一次提交,还有两次,它们发生在之前和之后。

【讨论】:

【参考方案3】:

实际上,如果可以的话,它会提交。如果不能成功提交,DDL 将失败。 阻止它提交的一种方法是违反延迟约束。

create table fred (id number);
alter table fred add constraint id_ck check (id >0) initially deferred;
insert into fred values (-1);
SQL> create table junk(val number);
create table junk(val number)
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02290: check constraint (GC_REF.ID_CK) violated
SQL> desc junk
ERROR:
ORA-04043: object junk does not exist

因此,如果您想防止隐式提交,请使用带有延迟约束的虚拟表。在其中插入违规行,您可以确保在解决违规行为之前无法提交事务(例如删除行)。

【讨论】:

【参考方案4】:

truncate tablealter tablecreate table 总是会导致提交。

为什么要在截断表时回滚?

【讨论】:

这可能是错误的表...回滚总是有充分的理由 :-) 您可以在 Postgres 中回滚这些命令。哦!在 RDB 中,你也可以回滚这些命令,但没人关心 :-)【参考方案5】:

Here 是 AskTom 的一篇文章,可能会有所帮助。来自文章:

“我想知道为什么 DDL 语句不在自治事务中执行(就像序列一样),所以它们不会影响任何待处理的用户事务......

你能澄清一下吗?

跟进 2003 年 6 月 24 日 - 美国/东部时间上午 7 点:

这与不这样做一样“令人困惑”。无论如何,你有atrans,所以如果你愿意,你可以。 "

所以,如果你真的需要,你可以把你的 DDL 放在一个自治事务中,然后做你想做的事。

编辑: 底线是,除非您明确地“颠覆” Oracle,否则 DDL 将执行提交。也就是说,如果您绝对要求在某个时间点执行提交,为什么不直接执行呢?

【讨论】:

【参考方案6】:

DDL 语句总是在执行后执行自动提交。

如果您希望它在发生故障时回滚(在服务器端),那么您可以设置某些标志来指示故障并采取适当的措施。

例如: 如果您创建了一个表 table1。 同时您正在其他表中插入一条记录。

但是由于某种原因插入失败(设置标志=真)。那么在这种情况下 您不能回滚,因为 create 语句是 ddl 语句,因此您可以通过 Drop 语句根据 flag 的值删除表(table1)来撤消数据库中的更改。

【讨论】:

【参考方案7】:

我同意 DCookie 和 Tom 关于自主交易的观点。我也打算说明这一点。

示例伪代码:

Do some DML
Call autonomous function, that performs DDL
Do some more DML
rollback or commit all the DML - your choice

不过,我认为这不是很有用。如果最初的 DML 和 DDL 接触同一个表/对象,它就不会工作。当您尝试执行 DDL 时会发生争用。就像任何两个相互阻塞的事务一样。如果它们是独立的对象,我想我不明白为什么执行顺序很重要。

【讨论】:

【参考方案8】:

“总是/从不”太强了。例如,来自 Oracle 18c 的像 CREATE PRIVATE TEMPORARY TABLE 这样的 DDL 不会 COMMIT 您的事务。

正常情况:

CREATE TABLE t(i INT);
INSERT INTO t(i) VALUES(21);

CREATE TABLE x(i INT);   -- same for CREATE GLOBAL TEMPORARY TABLE y(i INT); 
ROLLBACK;

SELECT * FROM t;
-- Output:
-- 21

但是如果你创建私有表:

CREATE TABLE t(i INT);
INSERT INTO t(i) VALUES(21);

CREATE PRIVATE TEMPORARY TABLE ORA$PTT_temp(i INT);  
-- or
CREATE PRIVATE TEMPORARY TABLE ORA$PTT_tab
AS
SELECT 1 AS c FROM dual;

ROLLBACK;
SELECT * FROM t;
-- Output:
-- no data found

db<>fiddle demo

【讨论】:

以上是关于DDL 语句总是给你一个隐式提交,还是你能得到一个隐式回滚?的主要内容,如果未能解决你的问题,请参考以下文章

自动回滚多个语句的隐式事务?

MySQL 的事务性 DDL 工作流

为啥要截断 DDL 语句?

如何获取hive建表语句

如何生成hive的建表语句

oracle中DDL DML指啥?