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 table 或 alter table 或 create 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 语句总是给你一个隐式提交,还是你能得到一个隐式回滚?的主要内容,如果未能解决你的问题,请参考以下文章