SAVEPOINT 有什么用?
Oracle 10.2 文档有一个good summary of the purpose of SAVEPOINT
使用ROLLBACK TO 语句,保存点撤消部分事务而不是整个事务。
和
在执行 INSERT、UPDATE 或 DELETE 语句之前标记隐式保存点。如果语句失败,则回滚到隐式保存点。通常,只是回滚失败的 SQL 语句,而不是整个事务;如果语句引发未处理的异常,则宿主环境(例如 SQL*Plus)确定回滚的内容。
你已经写了
在一个事务中进行 PL/SQL 中的所有查询
SAVEPOINT 在这种情况下是无用的 - 正如所说的那样,它用于撤销部分事务。如果每个查询都在一个事务中,并且在开始时强制保存点,那么它根本无法帮助我们。
程序
我认为你缺少一些东西:
-
您不能保证所有查询都位于该初始事务中。
使用每个步骤两个步骤执行批处理作业会占用大量临时空间。如果您运行这两个步骤而不在它们之间进行提交,那么您可能会用完临时空间,从而导致您和其他正在运行的进程出现问题。
我认为我们必须假设您可能有一个多阶段因此多程序的过程
您没有引发异常。这意味着如果您遇到数据错误,您将永远不会知道它。您必须向调用代码提出此异常以决定如何处理它。如果 Oracle 代码的每一层都引发异常,即问题是异常的,则语句将自动回滚。
您的程序至少必须是:
create or replace procedure transaction_safe(var in varchar2) is
begin
savepoint start_point;
exception when others then
rollback to start_point;
raise; -- the important part
end;
我们最终可能会得到一个大致如下所示的调用构造:
procedure run_process is
begin
transaction1;
commit;
transaction2;
commit;
exception when ...
...
end;
该过程实际上应该是一个调度程序链,但这样放置是为了便于查看。
如何使用?
我能想到三种可能性
1。靠它自己
begin
transaction1();
commit;
end;
没有直接的问题,调用代码正在执行提交逻辑,我们在您的过程中添加了一个异常,以便我们收到错误通知。如果我们阅读the documentation for ROLLBACK,它会说:
Oracle 建议您使用 COMMIT 或 ROLLBACK 语句显式结束应用程序中的事务。如果没有显式提交事务,程序异常终止,那么Oracle数据库会回滚最后一个未提交的事务。
您已经声明了COMMIT 和ROLLBACK,但这不是很明确,因为您的事务控制位于多个位置。如果我们把它放在同一个地方,它应该在调用代码而不是你的过程中,尽管这样做会使两者在功能上非常相似
procedure run_process is
begin
transaction1();
commit;
exception when others then
rollback;
raise;
end;
这也使代码更具可重用性。 transaction1() 可以根据需要从多个位置调用剥离事务逻辑。因为如果一切都崩溃了,那么一切都会回滚,我们不担心其他过程的事务控制逻辑很差,因为它们只在调用代码时提交。
2。执行多个“交易”
假设您现在在程序中引发了异常,并且我们没有在“事务”之间进行提交
procedure run_process is
begin
transaction1();
transaction2();
commit;
exception when others then
rollback;
raise;
end;
假设transaction1() 失败并回滚。在我们的外部异常处理程序中引发异常。不需要过程中的回滚逻辑。
以防万一,如果您没有在 transaction1() 中引发异常,那么您的数据可能会不一致,因为 transaction2() 将开始运行。
如果您在调度程序上运行 transaction1() 和 transaction2(),那么它们只是 (1) 的两个离散示例。
3。循环执行多个事务
换句话说,您的调用代码如下所示:
procedure run_process() is
begin
for i in (...) loop
begin
transaction1();
exception when others then
log();
end;
end loop;
end;
在这种情况下,您可能不希望单个故障阻止处理您的批次(如果您这样做是 (1) 的示例)。这是您撤消事务的一部分而不是整个事务的地方,因此使用保存点是有意义的。不过,我仍然会将它们放在调用代码中:
procedure run_process() is
begin
for i in (...) loop
begin
savepoint blah;
transaction1();
exception when others then
log();
rollback to blah;
end;
end loop;
end;
tl;dr
您不应该总是使用保存点,因此它们应该进入调用代码以确保代码的可重用性。