【问题标题】:PL/SQL Rollback Transaction with multiple package calls带有多个包调用的 PL/SQL 回滚事务
【发布时间】:2013-09-27 18:20:40
【问题描述】:

我是 Oracle PL/SQL 的新手,我正在尝试从使用 C# 的 SQL Server 调整为使用 PL/SQL 的 Oracle 自定义 Web 应用程序,用于多层应用程序。

我目前在回滚事务时遇到问题。由于我习惯于编写可重用代码,因此我使用这些类中的包和方法编写了我的 PL/SQL 代码。我的更新过程首先完成验证,如果验证成功,则调用一系列的各种包方法来完成保存。不幸的是,当调用 Rollback 函数时,我在更新过程的 EXCEPTION 部分中的回滚不会回滚所有内容。我不知道它为什么这样做。我的基本代码(虽然由于法律问题不准确)如下:

PROCEDURE SaveApplicationData(
variableName                  IN VARCHAR2 DEFAULT NULL,
--...
seq_id OUT INT )
AS
BEGIN
SET TRANSACTION NAME 'Transaction Name';

  --Save initial program record
  SaveNewRecord(variableName, seq_id);
  IF (seq_id != 0) THEN
    --If saved successfully, seq_id represents record ID
    package_class.secondarySaveMethod(variableName, seq_id);
    second_package_class.anotherSaveMethod(variableName, seq_id);  

END IF;

  COMMIT;
  htp.p('Sequence ID: ' || seq_id);
  htp.p('Saved the record"' || programName || '" successfully!');
EXCEPTION
WHEN OTHERS THEN
 utilityPackage.rollbacktransaction;
END SaveApplicationData;

utilityPackage.rollbacktransaction 包括一个 ROLLBACK 以及我们组织使用的自定义错误异常处理包。

本质上,它会回滚导致错误的部分,但是一旦它回滚该部分,它就会继续处理剩余的事务(并且不会回滚之前执行的代码块)。

如果这没有意义,请告诉我 - 并提前感谢您的帮助!

【问题讨论】:

  • 这听起来比实际需要的要复杂。也许有必要以这种方式做事。无论哪种方式,如果没有看到您的所有代码,我们很难提供任何建议。
  • APC - 在什么方面听起来太复杂了?就代码而言,它与我的代码结构相同……只是变量更少,名称不同。我的主要问题是在包方法中执行回滚时 - 它是否还应该回滚调用包方法的父过程中的代码?
  • 回滚会影响整个事务。除非你有保存点
  • 好的,这就是我认为它应该做的,但不确定,因为它没有按预期运行。我会检查发布更准确的代码。感谢您的快速回答。

标签: sql oracle plsql transactions rollback


【解决方案1】:

在 Oracle 之前来自 SQL Server 环境,我可以理解这种困惑。 Oracle 确实使用 BEGIN TRANSACTION。相反,事务是隐式为您启动的。

因此,我相信在您的情况下 SET TRANSACTION NAME 不是您想要做的,请参阅 SET TRANSACTION.

我建议从您的包中删除回滚代码并将其放在 C# 中。提交应该是调用者的责任。在 C# 中使用事务来保证在成功执行包时提交事务。

理想情况下,您的包结构应该更像这样。

declare
  ex_custom EXCEPTION;
  PRAGMA EXCEPTION_INIT( ex_custom, -20001 );
begin
  --Save initial program record
  SaveNewRecord(variableName, seq_id);
  IF (seq_id != 0) THEN
    --If saved successfully, seq_id represents record ID
    package_class.secondarySaveMethod(variableName, seq_id);
    second_package_class.anotherSaveMethod(variableName, seq_id);  
  ELSE
     -- seq_id invalid throw an exception
     RAISE_APPLICATION_ERROR(-20001,'Custom error')
  END IF;

  htp.p('Sequence ID: ' || seq_id);
  htp.p('Saved the record"' || programName || '" successfully!');
EXCEPTION
WHEN ex_custom THEN
  -- if needed we log it
  utility.log_exception;
  -- Raise it for the client to handle
  raise;
END SaveApplicationData;

【讨论】:

  • 布拉德利 - 感谢您的帮助!我对我的请求感到沮丧的部分原因是他们不允许使用服务器端语言。从 HTML 到数据库的所有内容都是用 PL/SQL 编写的。我正在努力改变我的思维过程,从使用客户端、业务和数据库层的分层应用程序改为在 PL/SQL 代码中逻辑分离它。在 PL/SQL 中完全创建类似的结构对我来说要困难得多。尽管如此,我认为我可以通过在调用存储过程中处理它来直接在 PL/SQL 中完成同样的事情。谢谢!
  • 您在调用存储过程中正确处理它是合适的。很高兴为您提供帮助!
  • 其他人的快速说明...我认为这是 Raise_application_error 而不是 raise_application_exception。否则效果很好!
  • 正确,raise_application_error 而不是 raise_application_exception。我已经编辑了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
  • 2012-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多