如果您正在执行事务的中途并执行 DDL 语句,例如截断表,则事务将提交。
我想知道这是否总是如此并且根据定义,或者是否有隐藏在某处的设置会回滚事务而不是提交。
谢谢。
编辑以澄清...
我不希望在截断后回滚。我只是想确认已经执行的语句绝对总是要在 DDL 之前提交。只是想确保没有人可以设置破坏我的代码的系统属性。
我理解在 DDL 之前和之后提交的必要性,但从概念上讲,我认为可以通过在 DDL 之前回滚和之后提交来实现相同的一致性要求。
如果您正在执行事务的中途并执行 DDL 语句,例如截断表,则事务将提交。
我想知道这是否总是如此并且根据定义,或者是否有隐藏在某处的设置会回滚事务而不是提交。
谢谢。
编辑以澄清...
我不希望在截断后回滚。我只是想确认已经执行的语句绝对总是要在 DDL 之前提交。只是想确保没有人可以设置破坏我的代码的系统属性。
我理解在 DDL 之前和之后提交的必要性,但从概念上讲,我认为可以通过在 DDL 之前回滚和之后提交来实现相同的一致性要求。
不,它会一直提交。
如果要回滚,则必须在 DDL 之前进行。
如果要将 DDL 与现有事务隔离,则必须在其自己的单独事务中执行它。
从技术上讲, DDL在执行之前和之后执行提交。
是的,来自 Cookie 的相同链接,但这是同一问题的不同方面。重要的是要理解这不仅仅是一次提交,还有两次,它们发生在之前和之后。
实际上,如果可以的话,它会提交。如果不能成功提交,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
因此,如果您想防止隐式提交,请使用带有延迟约束的虚拟表。在其中插入违规行,您可以确保在解决违规行为之前无法提交事务(例如删除行)。
截断表或更改表或创建表总是会导致提交。
为什么要在截断表时回滚?
这是一篇 AskTom 文章,可能会有所帮助。来自文章:
“我想知道为什么 DDL 语句不在自治事务中执行(就像序列一样),所以它们不会影响任何待处理的用户事务......
你能澄清一下吗?
跟进 2003 年 6 月 24 日 - 美国/东部时间上午 7 点:
那将与不这样做一样“令人困惑”。无论如何,你有atrans,所以如果你愿意,你可以。"
所以,如果你真的需要,你可以把你的 DDL 放在一个自治事务中,然后做你想做的事。
编辑:底线是,除非您明确地“颠覆”Oracle,否则 DDL 将执行提交。也就是说,如果您绝对要求在某个时间点执行提交,为什么不直接执行呢?
DDL 语句总是在执行后执行自动提交。
如果您希望它在发生故障时回滚(在服务器端),那么您可以设置某些标志来指示故障并采取适当的措施。
例如:如果您创建了一个表 table1。同时您正在其他表中插入一条记录。
但是由于某种原因插入失败(设置标志=真)。那么在这种情况下,您不能回滚,因为创建语句是 ddl 语句,因此您可以通过删除表(表 1)来撤消数据库中的更改,具体取决于flag 的值,通过 Drop 语句。
我同意 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 时会发生争用。就像任何两个相互阻塞的事务一样。如果它们是独立的对象,我想我不明白为什么执行顺序很重要。
“总是/从不”太强了。例如CREATE PRIVATE TEMPORARY TABLE
,来自 Oracle 18c 的 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