前提・実現したいこと
複数件の依頼に対して、JPAのStoredProcedureQuryを利用して、
件数分プロシージャコールを行い登録する処理を実装しています。
全て成功した場合のみcommitという作りにしています。
データベースはOracleです。
発生している問題・エラーメッセージ
問題は、StoredProcedureQueryのexecuteメソッドを繰り返しコールすると、
その都度カーソルがオープンされてしまい、300に到達した時点でORA-01000(最大オープン・カーソル数を超えました。)でエラーになってしまっています。
該当のソースコード
lang
1try{ 2 fac = Persistence.createEntityManagerFactory("xxx"); 3 em = fac.createEntityManager(); 4 tx = em.getTransaction(); 5 6 StoredProcedureQuery spq; 7 spq = em.createStoredProcedureQuery("YYYY.ZZZZ"); 8 spq.registerStoredProcedureParameter(1, Object.class, ParameterMode.IN); 9 spq.registerStoredProcedureParameter(2, Object.class, ParameterMode.IN); 10 spq.registerStoredProcedureParameter(3, Short.class, ParameterMode.OUT); 11 spq.registerStoredProcedureParameter(4, Short.class, ParameterMode.OUT); 12 tx.begin(); 13 for (List<String> rec : csv) { 14 String aa = rec.get(0); 15 String bb= rec.get(1); 16 spq.setParameter(1, aa); 17 spq.setParameter(2, bb); 18 // 実行 19 spq.execute(); 20 21 // エラーチェック 22 if(...){ 23 tx.rollback(); 24 return; 25 } 26 } 27 tx.commit(); 28}catch(Exception e){ 29 throw e; 30}finally{ 31 if(em != null)em.close(); 32 if(fac != null)fac.close(); 33}
lang
1CREATE OR REPLACE PACKAGE YYYY 2AS 3 /** ステータスコード **/ 4 G_RET_NORMAL NUMBER := 0; 5 G_RET_SQLERROR NUMBER := 1; 6 G_RET_PARAMERTER NUMBER := 2; 7 G_RET_DUPLICATION NUMBER := 3; 8 G_RET_NO_EXIST NUMBER := 4; 9 10 /** エラーNO **/ 11 G_ERR_NO_SUCCESS NUMBER := 0; 12 G_RET_ERROR NUMBER := 1; 13 14 PROCEDURE ZZZZ 15 ( 16 I_AAA IN TABLE_A.AAA%type, 17 I_BBB IN TABLE_A.BBB%type 18 O_STATUS OUT NUMBER, 19 O_ERROR_NO OUT NUMBER 20 ); 21END YYYY; 22/ 23 24CREATE OR REPLACE PACKAGE BODY YYYY 25IS 26 PROCEDURE ZZZZ 27 ( 28 I_AAA IN TABLE_A.AAA%type, 29 I_BBB IN TABLE_A.BBB%type 30 O_STATUS OUT NUMBER, 31 O_ERROR_NO OUT NUMBER 32 ) 33 IS 34 nCOUNT NUMBER := 0; 35 BEGIN 36 /* 入力パラメータチェック */ 37 ・・・ 38 39 /* データ存在チェック */ 40 BEGIN 41 SELECT 42 COUNT(1) 43 INTO 44 nCOUNT 45 FROM 46 TABLE_A 47 WHERE 48 AAA = I_AAA 49 AND BBB = I_BBB 50 ; 51 EXCEPTION 52 WHEN OTHERS THEN 53 O_STATUS := G_RET_SQLERROR; 54 O_ERROR_NO := SQLCODE ; 55 RETURN ; 56 END ; 57 IF nCOUNT > 0 THEN 58 O_STATUS := G_RET_DUPLICATION; 59 O_ERROR_NO := G_RET_ERROR ; 60 RETURN ; 61 END IF; 62 63 /* データ登録 */ 64 BEGIN 65 INSERT INTO 66 TABLE_A 67 ( 68 AAA, 69 BBB 70 ) VALUES( 71 I_AAA, 72 I_BBB 73 ); 74 EXCEPTION 75 WHEN OTHERS THEN 76 O_STATUS := G_RET_SQLERROR; 77 O_ERROR_NO := SQLCODE ; 78 RETURN ; 79 END ; 80 O_STATUS := G_RET_NORMAL ; 81 O_ERROR_NO := G_ERR_NO_SUCCESS ; 82 RETURN ; 83 EXCEPTION 84 WHEN OTHERS THEN 85 O_STATUS := G_RET_SQLERROR ; 86 O_ERROR_NO := SQLCODE ; 87 RETURN ; 88 89 END ZZZZ; 90END YYYY; 91/ 92
試したこと
プロシージャ内の処理を空にしても同様のエラーとなったため、おそらくプロシージャコール自体でカーソルを作成しているものと思われます。
V$OPEN_CURSORを確認したところ、確かに「BEGIN プロシージャ名; END;」というOPENが増幅していました。
JPAのStoredProcedureQueryを使わずにjava.sql.CallableStatementで呼び出したら、トランザクションの制御を含めてうまくいきましたので、JPA側の問題ではないかと思います。
ただ、コードの統一性を考慮して、実装はあくまでJPAで行いたいと考えています。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
あなたの回答
tips
プレビュー