0

こんにちは、wbsphere アプリケーションを tomcat に移植しています。同じサーバー上の 2 つのデータベースで作業する必要があり、Tomcat を atomikos transactionessential と統合しました。これは jta を使用した最初のプロジェクトであり、スキーマが同じサーバー上にあるため、xa と 2 フェーズ コミットは必要ないとオラクル データベース管理者から言われました。だから私はatomikosで非xaアプローチを使用しました。単一のスキーマでの次のコードは正常に機能します (コミットとロールバックは期待どおりです)。

utx.begin();
conn = //get connection 
if (sAzione.equals("1")) 
sql = "UPDATE parametri set valore =to_char(sysdate,'dd/mm/yyyy HH24:MI:ss') where id_parametri= 9 ";
//execute query
sql = "SELECT SEQ_LOTTO.nextval id FROM dual";
    //other operations
sql = "INSERT INTO LOTTO (id_lotto, numero_lotto, id_area, id_stato_lavorazione, id_autore, id_tipo)";
sql = sql + " VALUES (" + id + ", " + numero + ", " + request.getParameter("idArea") + ",1,"+ session.getAttribute("id_anagrafica")+ "," + request.getParameter("idTipo") + ")";
//execute import and release connection
utx.commit();

別の場所では、次のオラクル関数が呼び出され、両方のスキーマを変更しようとすると、コード 1 が返されます。pl-slq はわかりませんが、戻り値は最初の delete で例外が発生したことを意味するように見えますが、2 番目の削除は実行されてコミットされます。誰かが私にこの関数の意味を説明できますか? 以下は、関数とそれを呼び出すコードです

    create or replace FUNCTION FN_ELIMINA_RACC (idracc IN NUMBER, idlotto IN NUMBER)
   RETURN NUMBER
IS
   retvalue   NUMBER (1);
BEGIN
   retvalue := 1;

   DELETE FROM npa_collaudo.documento_raccomandata
         WHERE id_raccomandata = idracc;

   retvalue := 2;

   DELETE FROM raccomandata_out
         WHERE id_racc_out = idracc;

   retvalue := 3;

   IF idlotto != 0
   THEN
      UPDATE lotto
         SET numero_racc = numero_racc - 1
       WHERE id_lotto = idlotto;
   END IF;

   retvalue := 0;
   COMMIT;
   RETURN retvalue;
EXCEPTION
   WHEN OTHERS
   THEN
      RETURN retvalue;
END;

//the calling code
    utx.begin();
         //get connection
         sql = "FN_ELIMINA_RACC(" + idRacc + ", " + idLotto + ");";
                ret = connessioneDB.eseguiSP(sql);
         if (!(ret == 0)){
    throw new Exception("exception");
    utx.commit();
//since it returns 1 an exception is raised and rollback gets called

助けてくれてありがとう

編集:この(ひどい)コードをさらに調査し、あなたの答えのおかげで、悪名高い「eseguiSP」にこれを見つけました:

//strSQL is "FN_ELIMINA_RACC(..." 
DBOracle dbType = new DBOracle();
String SQL = "";
int retValue = 0;
SQL = " DECLARE ";
SQL = SQL + " ret NUMBER; ";
SQL = SQL + " BEGIN ";
SQL = SQL + " ret := " + strSQL; 
SQL = SQL + " END; ";
try {
stmt = conn.prepareCall(SQL);
retValue = stmt.executeUpdate(SQL); 
} catch (SQLException e) {
//retValue = false;
}
return retValue;

そして、私はそれを次のように変更しました:

c = ds.getConnection();
java.sql.CallableStatement cstmt = c.prepareCall("{?=call FN_ELIMINA_RACC(?,?)}");
cstmt.registerOutParameter(1,java.sql.Types.INTEGER);
cstmt.setInt(2, idRacc);
cstmt.setInt(3, idLotto);
cstmt.execute();
ret = cstmt.getInt(1);

今では正常に動作します (または少なくとも 0 を返します)。古いコードでは、raccomandata_out からレコードを削除しても、常に 1 が返されるのはなぜですか?

4

3 に答える 3

3

この関数は 1 を返すため、最初の削除で例外がスローされたことを示します。これにより、制御がブロックに切り替えられ、EXCEPTIONブロックは単純に戻ります。最初の削除の後の他のコードはまったく実行されるべきではありません。

例外ハンドラーは恐ろしいものです。例外をキャッチして破棄し、何が起こったかをほとんど伝えないフラグ値を返します。よりもわずかに優れていWHEN OTHERS THEN NULL;ます。これが書かれているように、どの例外が発生したかを知る方法はありません。例外ハンドラーを削除する (呼び出し元のコードが何らかの方法で例外をキャッチして処理できるようにする) か、少なくとも実際の例外メッセージ (SQLERRM) を何らかの方法でログに記録するように書き直す必要があります。

最も明白な推測は、コードが実行されるスキーマが他のスキーマのテーブルへの削除アクセス権を持っていないため、例外が発生していることです。関連する可能性のある Oracle の癖の 1 つは、格納された PL/SQL コード (この関数など) が、ロールを介して付与されたアクセスを利用できないことです。他のスキーマのオブジェクトへのアクセスは、ユーザーに直接許可する必要があります。

于 2011-03-30T14:56:18.610 に答える
2

この手順の例外ハンドラは特に役に立ちません。Oracleがスローしているエラーメッセージを完全に隠しています。例外ハンドラを完全に削除すると、エラー スタックはどうなりますか?

npa_collaudo.documento_raccomandata私の推測では、プロシージャの所有者には、テーブルから行を削除する権限がありません。しかし、実際に発生している例外を知らずにそれを知ることは不可能です。

于 2011-03-30T14:55:11.683 に答える
1

関数が 1 を返すことをどのように確認しますか? retスローしている例外は、値を報告していません。呼び出し自体が壊れている可能性があります。文字列;から末尾を削除してみてください。sqlその場合はより有用な例外を取得する必要がありますeseguiSP(sql)が、コードの他の場所に隠されている可能性があります (おそらく、1 が返されたように見える何かを追加している可能性がありますか?); どちらの削除も、それを 2 つのコマンドとして処理しようとしていて、2 つ目のコマンドが null であることを確認した場合にのみ文句を言う場合を除き、有効にすべきではありません。それはありそうにないように聞こえますが、決してわからないので、とにかくセミコロンを削除してみます.

また、値を に埋め込むのではなく、おそらく呼び出しにバインド パラメータを使用する必要がありますsql

また、ロールバックは例外で呼び出されると言いましたがutx.commit()、それは関数内のコミットでも冗長です。

于 2011-03-30T15:45:33.510 に答える