oracle - 调用过程时的 PL/SQL 事务

标签 oracle stored-procedures plsql transactions

我有两个主从组合表,用户和雇员(这是因为雇员是一种用户类型,并且还有其他类型的用户)。当将用户添加到系统时,在许多情况下,我还必须向 Employee 添加详细信息,更新这些表时也会发生同样的情况。这意味着我必须保证这两个操作(插入和更新)的原子性。

一个要求是使用存储的包和过程来执行 CRUD(表永远不会直接使用)。

我在 PL/SQL 中编写了以下简单示例,试图了解事务在这种情况下如何工作:

CREATE TABLE test_a
(
    campo_1 VARCHAR2(10) NOT NULL
);
CREATE TABLE test_b
(
    campo_2 VARCHAR2(10) NOT NULL
);
/
CREATE PROCEDURE ins_a
(
    texto_1 IN VARCHAR2
)
IS
BEGIN
    INSERT INTO test_a (campo_1) 
    VALUES (texto_1);
END;
/
CREATE PROCEDURE ins_b
(
    texto_2 IN VARCHAR2
)
IS
BEGIN
    INSERT INTO test_b (campo_2) 
    VALUES (texto_2);
END;
/
CREATE PROCEDURE ins_todos
(
    texto_1 IN VARCHAR2,
    texto_2 IN VARCHAR2
)
IS
BEGIN
    ins_a(texto_1);
    ins_b(texto_2);
END;
/

如果我运行

begin
ins_todos('alfa', '1234567846513216549');
end;
/

由于第二个参数的长度,该过程显然失败了,但第一个过程没有插入第一个参数,这让我感到惊讶,因为我预计第一个过程无论如何都会成功。

我的问题是:

  • 这是因为隐式事务在某处运行吗?
  • 如果是这样,我是否可以不必在 PL/SQL 代码中显式管理事务? (我仍然认为我应该在代码中明确使用事务。)
  • 如何确保在另一个过程中调用多个过程会尊重回滚和提交?我的目的是,如果其中一个内部过程抛出异常,则所有内部过程都必须回滚。
  • 最后,我可以在 PL/SQL 中完成所有这些操作,还是需要在 C# 数据访问层中对其进行管理?

最佳答案

"I expected the first procedure to succeed anyways."

它确实在自己的范围内取得了成功。但它是从另一个过程 ins_todos() 调用的,该过程因 ins_b() 失败而失败。

"Is this because of an implicit transaction running somewhere?"

事务是在发出 COMMIT 或 ROLLBACK 之前执行的所有操作的总和。您的代码不包含显式 COMMIT,因此它作为隐式事务运行。

"If so, does this free me from explicitly managing transaction in my PL/SQL code? (I still think I should explicitly use transactions in the code.)"

自由是一个棘手的概念。您需要清楚地了解哪些操作构成事务,即什么是工作单元。您需要正确管理事务,以确保数据库保持有效状态。这意味着您需要清楚何时发出 COMMIT 语句以及如何处理执行。

"How can I ensure that calling multiple procedures inside another procedure will respect rollbacks and commits? My purpose is that all inner procedures must rollback if one of them throws an exception."

您的测试代码表明这是默认行为。所以你所需要做的就是什么都不用做。

"can I do all of this in PL/SQL or do I need to manage it in my C# data access layer?"

这是一个架构决策。通常,调用堆栈顶部的代码负责完成事务。因此,这取决于您如何编写应用程序:使用您的示例,也许 COMMIT 应该放在 ins_todos() 过程中,或者它应该属于调用它的 C#。

所有 PL/SQL 程序都应该具有异常处理功能,包括日志记录。是否包括回滚是一个类似的架构决策。对于较低级别的 PL/SQL 程序来说,仅仅在调用堆栈上引发或重新引发异常是很常见的。

通常避免使用pragmaautonomous_transaction。这会创建嵌套事务,这将使您的数据库处于不一致的状态,除非您知道自己在做什么。自主事务的真正用例很少:记录到表是最常见的。

关于oracle - 调用过程时的 PL/SQL 事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45515356/

相关文章:

database - Oracle:查找主键 - PK 和 NN

nhibernate - 是否可以使用 NHibernate 调用存储过程并填充数据表?

java - 使用 '%' 作为 Java 中 SQL 参数中的通配符

sql - Oracle 专有连接 - 在多个条件下加入

oracle - 来自 Cursor Oracle 的确定性函数调用不起作用

sql - “ORA-00922: missing or invalid option” 尝试插入表时

sql-server - 如何将 SQL 探查器捕获的 'exec sp_executesql' 映射到 sql server 中的存储过程名称

python - 在使用用 PL/Python 编写的 bool 存储过程的 PostgreSQL CHECK 约束中,可以更新错误消息的详细信息吗?

oracle - 级联 LOVS - 默认值

oracle - 在 case 语句中返回 bool 值