调用过程时的PL / SQL事务

时间:2017-08-04 20:53:55

标签: oracle stored-procedures plsql transactions

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

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

我在PL / SQL中编写了以下简单示例,试图了解事务在此上下文中的工作方式:

<div class="container">
        <div class="row first-row slides">
        
            <div class="col-lg-3 col-md-3  col-sm-3 col-xs-3 product-categories-item">
            <div>
                <a routerLink="/banners">                
                        <!-- <img class="img-responsive" src="/assets/img/product-categories/cat_banners.png" alt="banners"> -->
                        <div>
                            <h3>Banners</h3>                       
                        </div>                
                </a>
               </div>
            </div>
            <div class=" col-lg-3 col-md-3  col-sm-3 col-xs-3  product-categories-item">
                 <div>
                 <a routerLink="/flags">                    
                      <!--   <img class="img-responsive"  src="/assets/img/product-categories/cat_flag.png" alt="flag"> -->
                        <div >
                            <h3 >Flags</h3>                       
                        </div>                    
                </a>
                </div>
            </div>
            <div class="col-lg-3 col-md-3  col-sm-3 col-xs-3  ">
            <div>
                <a routerLink="/retractable-banners">
                       <!--  <img class="img-responsive"  src="/assets/img/product-categories/cat_retractable.png" alt="Retractable Banners"> -->
                        <div>
                            <h3>Retractable Banners</h3>                       
                        </div>                    
                </a>
                </div>
            </div>
            <div class="col-lg-3 col-md-3  col-sm-3 col-xs-3 ">
            	<div>
                 <a routerLink="/signs">
                    
                       <!--  <img class="img-responsive"  src="/assets/img/product-categories/cat_signs.png" alt="Yard Signs"> -->
                        <div >
                            <h3 >Yards Signs</h3>                       
                        </div>                    
                </a>
                </div>
            </div> 
          
          
            <div class="col-md-3  col-sm-3 col-xs-3 ">
            <div>
                <a routerLink="/banner-stands">                    
                       <!--  <img class="img-responsive"  src="/assets/img/product-categories/cat_stands.png" alt="Stands"> -->
                        <div >
                            <h3 >Banner Stands</h3>                       
                        </div>                    
                </a>
                </div>
            </div>
            <div class="col-lg-3 col-md-3  col-sm-3 col-xs-3 ">
            <div>
                 <a routerLink="/custom-table-throws">                    
                        <!-- <img class="img-responsive"  src="/assets/img/product-categories/cat_table.png" alt="table covers"> -->
                        <div >
                            <h3 >Table Covers</h3>                       
                        </div>                    
                </a>
                </div>
            </div>
            <div class="col-lg-3 col-md-3  col-sm-3 col-xs-3  ">
            <div>
                 <a routerLink="/canvas-prints">                    
                       <!--  <img class="img-responsive"  src="/assets/img/product-categories/cat_canvas.png" alt="Canvas Prints"> -->
                        <div >
                            <h3>Canvas Prints</h3>                       
                        </div>                    
                </a>
                </div>
            </div>
            <div class="col-lg-3 col-md-3  col-sm-3 col-xs-3 ">
            <div>

                <a routerLink="/hardware-accessories">                    
                        <!-- <img class="img-responsive"  src="/assets/img/product-categories/cat_hardware.png" alt="hardware"> -->
                        <div >
                            <h3 >Hardware &amp; Accessories</h3>                       
                        </div>                    
                </a>
                </div>
            </div> 
                      
        </div>
    </div>

如果我跑

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;
/

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

我的问题是:

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

2 个答案:

答案 0 :(得分:2)

  

“我预计第一个程序无论如何都会成功。”

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

  

“这是因为隐式事务在某处运行吗?”

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

  

“如果是这样,这是否使我免于在PL / SQL代码中明确管理事务?(我仍然认为我应该在代码中明确使用事务。)”

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

  

“我怎样才能确保在另一个过程中调用多个过程会尊重回滚和提交?我的目的是所有内部过程必须回滚,如果其中一个抛出异常。”

您的测试代码表明这是默认行为。所以你所需要做的就是一无所获。

  

“我可以在PL / SQL中完成所有这些操作,还是需要在C#数据访问层中管理它?”

这是一个架构决策。通常,它是callstack顶部的代码,负责完成事务。所以它取决于你如何编写应用程序:使用你的例子,也许COMMIT应该进入ins_todos()过程,或者它应该属于调用它的C#。

所有PL / SQL程序都应该有异常处理,包括日志记录。是否包含ROLLBACK是一个类似的架构决策。较低级别的PL / SQL程序通常只是在callstack上引发或重新引发异常。

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

答案 1 :(得分:0)

执行ins_todos过程时,由于varchar2长度约束为10个字符,因此对ins_b的调用失败。此故障回滚当前事务中的所有sql语句。该事务以第一次插入test_a表开始。

如果你真的希望第一个插入sql独立于第二个提交,那么你将使用pragma autonomous_transaction。

例如:

CREATE or replace PROCEDURE ins_a
(
    texto_1 IN VARCHAR2
)
IS
  pragma autonomous_transaction;
BEGIN
    INSERT INTO test_a (campo_1) 
    VALUES (texto_1);
  commit;
END;
/

无论第二个插入成功还是失败,这都会将插入提交到test_a中。

这里要理解的重要信息是,除非被捕获和处理,否则任何异常都将导致事务回滚除自主事务中提交的工作之外的所有工作。