2017-08-04 7 views
1

私は、マスターディテールの構成UserとEmployeeに2つのテーブルを持っています(これは、Employeeがユーザーのタイプであり、他のタイプのユーザーがいるためです)。ユーザーがシステムに追加されると、多くの場合、従業員に詳細を追加する必要があります。これらのテーブルを更新する場合も同様です。つまり、これらの2つの操作(挿入と更新)のアトミック性を保証する必要があります。プロシージャを呼び出すときのPL/SQLトランザクション

1つの要件は、格納されたパッケージとプロシージャを使用して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#データアクセス層で管理する必要はありますか?
+1

'トランザクションを開始するプロシージャを実行すると、暗黙のトランザクションがどこかで実行されているためですか?もしエラー - データベースがあなたのすべての変更をロールバックするならば、 – are

答えて

2

"とにかく最初の手順が成功すると思っていました。"

これは、独自の範囲で成功しました。しかし、ins_b()が失敗したために別の手順ins_todos()が呼び出されました。

"これは、暗黙のトランザクションがどこかで実行されているためですか?「

トランザクションは、すべての操作の合計がCOMMITまたはROLLBACKの発行まで実行される。あなたのコードでは、COMMIT、明示的に含まれていないので、はい、それは暗黙のトランザクションとして動作します。

"もしそうなら、私のPL/SQLコードでトランザクションを明示的に管理できないのですか? (私はまだ、私は明示的にコード内でトランザクションを使用すべきだと思う。)」

自由がトリッキーな概念です。あなたは操作が作業単位が何であるか。あなたが必要とする、すなわち、トランザクションを構成するの明確な理解を持っている必要があります

"データベースを有効な状態に保つために、トランザクションを適切に管理するにはどうすればよいですか?別のプロシージャ内のプロシージャはロールバックとコミットを尊重しますか?私の目的は、それらの1つが例外をスローした場合、すべての内部手続きをロールバックしなければならないということである。「

あなたのテストコードは、これはデフォルトの動作であることを示している。だから、あなたが必要とするすべては何もありません。

」 PL/SQLでこれをすべて行うことはできますか?それとも、C#データアクセス層でそれを管理する必要がありますか?」

これはアーキテクチャ上の決定です。通常はコールスタックの先頭にあるコードです。取引を確定する責任があります。したがって、あなたの申請書の書き方によって異なりますあなたの例を使用して、おそらくCOMMITはins_todos()プロシージャに入っていなければならないかもしれません。あるいは、それを呼び出すC#に属している必要があります。

すべてのPL/SQLプログラムには、ロギングを含む例外処理が必要です。それがROLLBACKを含むかどうかは、同様のアーキテクチャ上の決定です。コール・スタックの上で例外を発生または再発生させるだけの下位レベルのPL/SQLプログラムでは一般的です。

一般的にpragma autonomous_transactionの使用を避けてください。これはネストされたトランザクションを作成します。ネストされたトランザクションは、あなたが何をしているのか分からない限り、データベースを不整合な状態にしてしまいます。自律型トランザクションでは、本物のユースケースはほとんどありません。テーブルへのロギングが最も一般的です。

+1

自由は高速道路につながる埃の多い道です。 –

0

ins_todosプロシージャを実行すると、10文字のvarchar2長さ制約のためにins_bへの呼び出しが失敗することが予想されます。この障害は、現在のトランザクション内のすべてのSQL文をロールバックします。トランザクションは、最初にtest_aテーブルに挿入して開始されます。

最初のinsert sqlを2番目のものとは別にコミットしたい場合は、プラグマ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への挿入をコミットしません。

ここで理解しておくべき重要な情報は、キャッチされて処理されない限り、トランザクションが自律型トランザクション内でコミットされた作業を除くすべての作業をロールバックさせることです。

+1

OPは、「私の目的は、それらのうちの1つが例外をスローすると、すべての内部プロシージャがロールバックされなければならないということです」だから「プラグマautonomous_transaction」は、 – APC

関連する問題