在隐式提交的情况下强制回滚
Force rollback in case of an implicit commit
SQL 或 PLSQL 中是否有一种方法可以确保没有提交任何内容?因为,有时会调用 function/procedure 并且结果未知。例如,它可以触发隐式提交。有什么办法可以避免吗?
我在 Oracle 数据库中给出示例
这是针对 SQL 语句 DML。
SQL> set transaction read only;
Transaction set.
SQL> update t set t=14;
update t set t=14
*
ERROR at line 1:
ORA-01456: may not perform insert/delete/update operation inside a READ ONLY
transaction
这用于调用其中包含提交的过程。
SQL>alter session DISABLE COMMIT IN PROCEDURE ;
SQL>exec procedureHavingCommit(10);
BEGIN procedureHavingCommit(10); END;
*
ERROR at line 1:
ORA-00034: cannot COMMIT in current PL/SQL session
ORA-06512: at "ND210.DRMOP_UTIL", line 332
ORA-06512: at "ND210.DRMOP_UTIL", line 1664
ORA-00034: cannot COMMIT in current PL/SQL session
ORA-06512: at line 1
我将对上面的 ALTER SESSION DISABLE COMMIT IN PROCEDURE 答案投赞成票。但是,正如已经指出的那样——如果您已经在进行交易,那将不起作用。也就是说,您处于打算提交的情况,但不希望调用的过程在您准备好之前提交。
在这种情况下,我所做的是写一些东西来检测是否发生了 COMMIT。它不会阻止提交,但它会导致我的程序出错——即使提交不会造成任何伤害。
这样,我可以 100% 确定在测试期间检测到 COMMIT 正在发生并且可以在设计中处理它。
这里是 link 对我正在描述的方法的描述:
如果您想确保不会修改任何内容,"set transaction read only" 是正确的答案。
否则:如果您正在编写一些调用其他程序员编写的其他过程的代码,并且您主要担心这些其他过程可能会发出不需要的提交(或者将来可能会被修改以发出不需要的提交),所以您想要在它们造成损害之前抓住它们,好吧,我有一个解决方案,你会发现它很有用,我目前在我的代码中正是出于这个目的使用它:
假设您的程序执行此操作:
procedure MyProcedureThatModifiesData is
begin
update mytables....
SomeOthersProcedure;
update myothertables ...;
commit; -- having a commit in a stored procedure
-- is a bad idea: i wrote this only to mimick the global
-- application behaviour
end;
并且您要确保,如果 SomeOtherProcedure 的作者修改了他的过程,在其中插入了一个提交,则该提交将被阻止并回滚。
在我的解决方案中,代码变成了这样:
procedure MyProcedureThatModifiesData is
begin
pkg_block_unwanted_commits.DisableCommits; // <<!!
update mytables....
SomeOthersProcedure;
update myothertables ...;
pkg_block_unwanted_commits.ReenableCommits; // <<!!
commit; -- having a commit in a stored procedure
-- is a bad idea: i wrote this only to mimick the global
-- application behaviour
end;
让我解释一下使它成为可能的想法:您所需要的只是一个包含延迟约束的 table。
仅当您发出 "commit" 时才检查延迟约束:就数据未提交而言,它可能违反约束,但如果您尝试提交,则整个事务将回滚并引发 oracle 错误。
现在重点是:如果您在程序开始时故意插入一些违反延迟约束的数据,您将获得您所要求的:回滚而不是提交。
要重新启用提交,您所要做的就是删除违反约束的数据。
一个基本的实现可能是这样的:
procedure MyProcedureThatModifiesData is
begin
-- this update "disables" the commits
update myspecialtable set
myfield=unacceptable_value_that_violates_the_constraint;
update mytables....
SomeOthersProcedure;
update myothertables ...;
-- this update "re-enables" the commits
update myspecialtable set
myfield=valid_value;
commit;
end;
上述基本实现的进一步步骤是使 "myspecialtable" 成为全局临时值 table(种类:在提交时保留行)因此它将仅包含在生命周期内写入的临时值您的 oracle 会话,它不会永久存储在数据库中。此外,通过这种方式,其他会话将能够在这个特殊的 table 中写入自己的数据,而不会干扰您的 table.
完整的解决方案是这个:
create or replace package pkg_block_unwanted_commits is
-- we will implement these two in order to allow nested calls:
-- each DisableCommit must be paired with her EnableCommits.
-- commits will be actually enabled only when each DisableCommit (including
-- nested calls) has been closed by her pairing EnableCommit
procedure DisableCommits;
procedure ReenableCommits;
end;
/
-- this is the temporary table we will use for the above
create global temporary table tbl_block_unwanted_commits
(
-- this primary key, along with the "chk_only_one_row" constraint ensures that
-- this table can contain only one row
only_one_row char(1) default 'X' primary key,
-- it keeps track of the number of "opened" DisableCommits calls:
-- we can commit only if nest_counter is zero
nest_counter number not null
)
on commit preserve rows
/
-- this one, considering that "only_one_row" is the primary key
-- ensures we will have only one row in the table (just to be safe)
alter table tbl_block_unwanted_commits add constraint
chk_only_one_row check (only_one_row='X')
/
-- this is just to reveal errors in our program if we call EnableCommits without having called DisableCommits
-- (mispaired calls)
alter table tbl_block_unwanted_commits add constraint
chk_unbalanced_enables check (nest_counter >=0)
/
-- this one is the constraint that actually does the trick of blocking commits
-- we can commit only if whe have active calls to "disablecommits" that have not been paired with corresponding "ReenableCommits"
alter table tbl_block_unwanted_commits add constraint
chk_blocked_commits check (nest_counter = 0) deferrable initially deferred
/
create or replace package body pkg_block_unwanted_commits is
procedure DisableCommits is
begin
update tbl_block_unwanted_commits set nest_counter = nest_counter +1;
if sql%notfound then
insert into tbl_block_unwanted_commits(only_one_row,nest_counter)
values ('X',1);
end if;
end;
procedure ReenableCommits is
begin
update tbl_block_unwanted_commits set nest_counter = nest_counter -1;
end;
end;
/
希望这对您有所帮助
SQL 或 PLSQL 中是否有一种方法可以确保没有提交任何内容?因为,有时会调用 function/procedure 并且结果未知。例如,它可以触发隐式提交。有什么办法可以避免吗?
我在 Oracle 数据库中给出示例
这是针对 SQL 语句 DML。
SQL> set transaction read only;
Transaction set.
SQL> update t set t=14;
update t set t=14
*
ERROR at line 1:
ORA-01456: may not perform insert/delete/update operation inside a READ ONLY
transaction
这用于调用其中包含提交的过程。
SQL>alter session DISABLE COMMIT IN PROCEDURE ;
SQL>exec procedureHavingCommit(10);
BEGIN procedureHavingCommit(10); END;
*
ERROR at line 1:
ORA-00034: cannot COMMIT in current PL/SQL session
ORA-06512: at "ND210.DRMOP_UTIL", line 332
ORA-06512: at "ND210.DRMOP_UTIL", line 1664
ORA-00034: cannot COMMIT in current PL/SQL session
ORA-06512: at line 1
我将对上面的 ALTER SESSION DISABLE COMMIT IN PROCEDURE 答案投赞成票。但是,正如已经指出的那样——如果您已经在进行交易,那将不起作用。也就是说,您处于打算提交的情况,但不希望调用的过程在您准备好之前提交。
在这种情况下,我所做的是写一些东西来检测是否发生了 COMMIT。它不会阻止提交,但它会导致我的程序出错——即使提交不会造成任何伤害。
这样,我可以 100% 确定在测试期间检测到 COMMIT 正在发生并且可以在设计中处理它。
这里是 link 对我正在描述的方法的描述:
如果您想确保不会修改任何内容,"set transaction read only" 是正确的答案。
否则:如果您正在编写一些调用其他程序员编写的其他过程的代码,并且您主要担心这些其他过程可能会发出不需要的提交(或者将来可能会被修改以发出不需要的提交),所以您想要在它们造成损害之前抓住它们,好吧,我有一个解决方案,你会发现它很有用,我目前在我的代码中正是出于这个目的使用它:
假设您的程序执行此操作:
procedure MyProcedureThatModifiesData is
begin
update mytables....
SomeOthersProcedure;
update myothertables ...;
commit; -- having a commit in a stored procedure
-- is a bad idea: i wrote this only to mimick the global
-- application behaviour
end;
并且您要确保,如果 SomeOtherProcedure 的作者修改了他的过程,在其中插入了一个提交,则该提交将被阻止并回滚。
在我的解决方案中,代码变成了这样:
procedure MyProcedureThatModifiesData is
begin
pkg_block_unwanted_commits.DisableCommits; // <<!!
update mytables....
SomeOthersProcedure;
update myothertables ...;
pkg_block_unwanted_commits.ReenableCommits; // <<!!
commit; -- having a commit in a stored procedure
-- is a bad idea: i wrote this only to mimick the global
-- application behaviour
end;
让我解释一下使它成为可能的想法:您所需要的只是一个包含延迟约束的 table。 仅当您发出 "commit" 时才检查延迟约束:就数据未提交而言,它可能违反约束,但如果您尝试提交,则整个事务将回滚并引发 oracle 错误。
现在重点是:如果您在程序开始时故意插入一些违反延迟约束的数据,您将获得您所要求的:回滚而不是提交。 要重新启用提交,您所要做的就是删除违反约束的数据。
一个基本的实现可能是这样的:
procedure MyProcedureThatModifiesData is
begin
-- this update "disables" the commits
update myspecialtable set
myfield=unacceptable_value_that_violates_the_constraint;
update mytables....
SomeOthersProcedure;
update myothertables ...;
-- this update "re-enables" the commits
update myspecialtable set
myfield=valid_value;
commit;
end;
上述基本实现的进一步步骤是使 "myspecialtable" 成为全局临时值 table(种类:在提交时保留行)因此它将仅包含在生命周期内写入的临时值您的 oracle 会话,它不会永久存储在数据库中。此外,通过这种方式,其他会话将能够在这个特殊的 table 中写入自己的数据,而不会干扰您的 table.
完整的解决方案是这个:
create or replace package pkg_block_unwanted_commits is
-- we will implement these two in order to allow nested calls:
-- each DisableCommit must be paired with her EnableCommits.
-- commits will be actually enabled only when each DisableCommit (including
-- nested calls) has been closed by her pairing EnableCommit
procedure DisableCommits;
procedure ReenableCommits;
end;
/
-- this is the temporary table we will use for the above
create global temporary table tbl_block_unwanted_commits
(
-- this primary key, along with the "chk_only_one_row" constraint ensures that
-- this table can contain only one row
only_one_row char(1) default 'X' primary key,
-- it keeps track of the number of "opened" DisableCommits calls:
-- we can commit only if nest_counter is zero
nest_counter number not null
)
on commit preserve rows
/
-- this one, considering that "only_one_row" is the primary key
-- ensures we will have only one row in the table (just to be safe)
alter table tbl_block_unwanted_commits add constraint
chk_only_one_row check (only_one_row='X')
/
-- this is just to reveal errors in our program if we call EnableCommits without having called DisableCommits
-- (mispaired calls)
alter table tbl_block_unwanted_commits add constraint
chk_unbalanced_enables check (nest_counter >=0)
/
-- this one is the constraint that actually does the trick of blocking commits
-- we can commit only if whe have active calls to "disablecommits" that have not been paired with corresponding "ReenableCommits"
alter table tbl_block_unwanted_commits add constraint
chk_blocked_commits check (nest_counter = 0) deferrable initially deferred
/
create or replace package body pkg_block_unwanted_commits is
procedure DisableCommits is
begin
update tbl_block_unwanted_commits set nest_counter = nest_counter +1;
if sql%notfound then
insert into tbl_block_unwanted_commits(only_one_row,nest_counter)
values ('X',1);
end if;
end;
procedure ReenableCommits is
begin
update tbl_block_unwanted_commits set nest_counter = nest_counter -1;
end;
end;
/
希望这对您有所帮助