【问题标题】:batch procedure, when to commit transactions?批处理程序,何时提交事务?
【发布时间】:2012-03-28 17:40:06
【问题描述】:

我对 PL-SQL 还是很陌生,尽管我对其他 RDBMS 有很多 db 经验。这是我当前的问题。

procedure CreateWorkUnit
is
update workunit 
set workunitstatus = 2 --workunit loaded 

where
    SYSDATE between START_DATE and END_DATE
and workunitstatus = 1 --workunit created;

--commit here?

call loader; --loads records based on status, will have a commit of its own

update workunit wu
set workunititemcount = (select count(*) from workunititems wui where wui.wuid = wu.wuid)
where workunitstatus = 2 

因此,无论有没有提交语句,我看到的行为是我必须执行两次。一旦翻转状态,加载程序将在第二次执行时运行。我想一口气跑完。

我会很感激任何预言智慧的话。

谢谢!

【问题讨论】:

  • 所以您的问题在于您没有向我们展示的代码,即 LOADER 本身。出于某种原因,它没有反映工作状态的变化。原因有很多,如果没有看到代码,很难提出建议。
  • 那么“call loader”到底是做什么的呢?
  • 除了缺少的loader,(a) 你的procedure CreateWorkUnit 代码片段不清楚:它是在一个匿名块中,还是它前面有一个CREATE 命令? (b) 你怎么知道CreateWorkUnit 被执行了? (c) 它缺少END

标签: sql oracle transactions plsql


【解决方案1】:

何时在批处理过程中提交事务?这是一个很好的问题,尽管它似乎只与您发布的代码的问题模糊相关。但无论如何,让我们回答它。

当 PL/SQL 过程完成一个工作单元时,我们需要提交。一个工作单元是一个业务交易。这通常在程序的末尾,即 EXCEPTION 部分之前的最后一条语句。

有时甚至没有。正确提交或回滚的决定取决于调用堆栈的顶部。如果我们的 PL/SQL 是从客户端调用的(可能是用户单击屏幕上的按钮),那么客户端可能应该发出提交。

但是批处理管理自己的提交(并在出现错误的情况下回滚)并不是不合理的。但要点是唯一最顶层的程序应该发出 COMMIT。如果一个过程调用其他过程,那些被调用的程序不应发出提交或回滚。如果他们应该处理任何错误(日志等)并将它们重新引发到调用程序。让它解码是否回滚。因为所有被调用程序都在同一个会话中运行,因此在同一个事务中运行:被调用程序中的回滚将恢复批处理中的所有更改。那是不对的。同样的推理也适用于提交。

您有时会阅读有关使用间歇性提交将长时间运行的进程分解为较小单元的建议,例如每 1000 次插入。这是一个不好的建议,有几个原因,并不是所有的都与交易有关。相关的有:

  1. 发出提交可释放资源锁定。这是ORA-1555 Snapshot too old 错误的原因。
  2. 它还会影响读取一致性,这仅适用于语句和/或事务级别。这是ORA-1002 Fetch out of sequence 错误的原因。
  3. 它会影响可重新启动性。如果程序在处理 30% 的记录时失败,我们是否可以确信在重新运行批处理时它只会处理剩余的 70%?
  4. 一旦我们提交记录,其他会话就可以看到这些更改:其他用户看到部分更改的数据视图是否有意义?

所以,“Oracle 智慧”的话是:始终将数据库事务与业务事务对齐,每个工作单元只有一次提交。


有人提到autonmous transactions 作为在子流程中发布提交的一种方式。这通常是个坏主意。在自治事务中所做的更改对其他会话可见,但对我们自己的会话不可见。这很少有道理。它还会产生与我之前讨论过的可重新启动性相同的问题。

自动事务唯一可接受的用途是记录活动(错误日志、跟踪、审计记录)。无论在更广泛的事务中发生什么,我们都需要这些数据持续存在。几乎可以肯定,对 pragma 的任何其他使用都是 porr 设计的解决方法,这实际上只会使问题变得更糟。

【讨论】:

  • 非常感谢这里提供的志愿者信息。我所有的背景都是 mssql,我现在的商店是 oracle 客户。很高兴,我可以编写 sql 标准并且我仍然很高效,但我必须习惯编写游标......它们在临时空间上更容易:)
【解决方案2】:

您可能不需要在 pl/sql 过程中提交。您在另一个过程中调用的过程将使用相同的会话,因此您无需提交。顺便说一句,如果会话回滚或出现异常,程序必须完全回滚。

【讨论】:

  • 可以在 pl/sql 中提交。
  • 你不仅可以在一个过程中提交,你还可以让它自治,这将阻止它提交主事务(调用它的那个)
  • @BurhanAli - 当然,我们可以在 PL/SQL 程序中提交。问题是我们是否应该,如果应该,在哪里?被调用程序中的提交可能位于错误的位置:正确提交或回滚的决定取决于调用堆栈的顶部。在某些情况下,这不一定是真的,但它们非常罕见。
  • @ABCade - 同样,我们当然可以使用自动交易。但我们应该吗?几乎可以肯定不是。自治事务的唯一有效用途是写入日志或跟踪记录。尝试用自治事务解决任何其他问题,就意味着你现在遇到了两个问题。
  • @APC 我没有对您是否应该发表任何评论。我只是对答案中的陈述提出异议:“您可能不会在 pl/sql 过程中提交。”
【解决方案3】:

我错误地分类了我的问题。我认为这是一个事务问题,实际上它是我的标志之一没有按预期设置。当我期待 0 时,数字字段为空。

对此感到抱歉。 乔什·罗宾逊

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-22
    • 2015-08-18
    • 2016-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-01
    相关资源
    最近更新 更多