PreparedStatementの使い方と注意点

このQ&Aのポイント
  • PreparedStatementを使用する際には、close処理を忘れずに行うことが重要です。
  • close処理が抜けていると、ORA-1000 最大オープン・カーソル数を超えるエラーが発生することがあります。
  • forループ内でのclose処理は避け、ループの外で行うようにしましょう。また、オラクルの設定にも注意が必要です。
回答を見る
  • ベストアンサー

PreparedStatementについて質問

すみません。PreparedStatementについて勉強中です。 現在、下記の形で更新処理をしようとしています。 { for(int i ; i<500;i++){      //PreparedStatementを使って更新処理      classA.updateData();   } }finally{ //PreparedStatementやResultSetのclose処理  classA.close(); } 実行すると、[ORA-1000 最大オープン・カーソル数を超えました 。]が発生してしまいました。 ネットで探してみると、close処理が抜けていたりすると発生すると書いてありました。 close位置が悪いのでしょうか。(for文の中に入れる?) オラクルの設定が悪いのでしょうか。 分かりづらい質問で申し訳ないです。 ご指導、また参考になるサイト様がありましたら教えていただきたいです。 よろしくお願いいたします。

  • Java
  • 回答数1
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • root139
  • ベストアンサー率60% (488/809)
回答No.1

classA.updateData() の中身が分からないとハッキリしたことは言えないのですが、エラーメッセージからしてOracleに設定されている最大カーソル数より多くの ResultSet を同時にオープンしているのでしょう。 classA.updateData() の中で PreparedStatement/ResultSet オブジェクトを取得していて、かつ close をしていなければ、少なくとも500個は同時にオープンしていることになるかと。(参照が外れていてGCが走ればそうならない可能性も有りますが) また、classA.close() の中では classA.updateData() で開いた分(500個?)の close を行っているでしょうか? たとえ、一つの PreparedStatement 変数/フィールドしか使っていなくても、複数のオブジェクトを生成している場合はそれぞれのオブジェクトに close が必要となります。 悪い例) -------------------------------------------- PreparedStatement pstmt = null; try { // 1個目の PreparedStatement オブジェクト pstmt = connection.prepareStatement(sql1); ・ ・ ・ // 2個目の PreparedStatement オブジェクト pstmt = connection.prepareStatement(sql2); ・ ・ ・ } finally { pstmt.close(); // 2個目の PreparedStatement しかcloseされない! } ---------------------------------------------------- ※ 簡単にする為に例外処理などは省略しています。 メモリ以外のリソースに関わる PreparedStatement などについては、原則的に一つのメソッド内でオープンとクローズを行うと良いです。どうしても分けなければならない場合も有るでしょうが。

poipoi2011
質問者

お礼

分かりにくい説明にご回答ありがとうございます。 classA.updateData()のなかは、端よって書くと PreparedStatement pstm = con.prepareStatement("UPDATE テーブルA SET 項目A=?"); pstm.setInt(1, 更新値); pstm.executeUpdate(): という感じです。 PreparedStatement,ResultSetで勉強不足で分らないことも多いのですが・・・ 確かに、ループの分だけ「pstmt」が作られます。 ということは、同じSQL文で更新値が違うだけだと if(pstmt!=null){ pstmt = connection.prepareStatement(sql); } とすれば大丈夫ということでしょうか。

関連するQ&A

  • DBのコネクションのclose処理で例外が発生した場合

    DBのコネクションのclose処理で例外が発生した場合 DBアクセスが終わった後、finallyでResultSetやConnection、PreparedStatementのclose処理を行うと思います。 } finally { if (result != null) { try { result.close(); } catch (SQLException e) { } } if (ps != null) { try { ps.close(); } catch (SQLException e) { } } if (conn != null) { try { conn.close(); } catch (SQLException e) { } } } 上記では各close処理で例外が発生した場合、何もしていませんがこのあたりの処理は何を行うべきなのでしょうか。 例えばログ出力をして例外をそのまま上位にスローするなどでしょうか。 close処理で例外が発生するのは余程のことだと思うのですが、ログ出力以外で何かやるべき処理はありますでしょうか。

    • ベストアンサー
    • Java
  • WebSphere/DB2/ResultSet close/Exception

    WebSphereを使って、Listenerで取得したデータソースを利用していますが、 String sql1 = "SELECT A1 FROM TEST1"; String sql2 = "SELECT B2 FROM TEST2 WHERE B1 = ?"; Connection conn = datasource.getConnection(); PreparedStatement ps1 = conn.preparedStatement(sql1); ResultSet rs1 = ps1.executeQuery(); while(rs1.next()){ PreparedStatement ps2 = conn.preparedStatement(sql2); ps2.setString(1,rs1.getString("A1")); ResultSet rs2 = ps2.executeQuery(); ps2.close(); } このロジックで、ps2をクローズすると、ps1で取得したResultSet rs1がクローズされるというExceptionが発生してしまいます。 (ループして戻ったときにrs1.next()でexceptionが起こる) なにか対処方法があるかご存知の方いらっしゃいましたら、よろしくお願いいたします。

    • ベストアンサー
    • Java
  • requestについて困っています。

    下記のbooleanの結果を他のサーブレットで取得して、結果ごとに"mapping.findForward("")"の処理をしたいのですが、取得の仕方が分かりません。お願い致します。 <MemberDAO.java> ・・・ public boolean isEntriedMail(String member_mail) throws SQLException{ Connection con = ds.getConnection(); PreparedStatement stmt = con.prepareStatement(ISENTRIEDSQL); ResultSet rs = null; try{ stmt.setString(1,member_mail); rs = stmt.executeQuery(); if(rs.next()){ int count = rs.getInt(1); if(count == 0){ return false; } } }catch(SQLException ex){ return true; }finally{ if(rs != null){ rs.close(); } stmt.close(); con.close(); } return true; }

  • 複数の派生クラスオブジェクトを一括して取り扱う方法

    いつもお世話になっています。 C++でプログラムをしています。 classAの派生クラスとして、 classA-1、classA-2を作りました。 classAのオブジェクトには、 親クラスにおいて、重複しないIDを 定義しています。 classA{...} classA-1():public A classA-2():public A classA-1 A1[1000]; classA-2 A2[2000]; ここで、クラスAオブジェクト (派生クラスを含む)のうち、 特定のIDのオブジェクト、 例えば、ID=100番のものを 取り出して、何某かの処理をしたいのですが、 現在は、 for(i=0;i<1000;i++){ if(A1[i] == 100){...} } for(i=0;i<2000;i++){ if(A2[i] == 100){...} } のようにしています。 しかし、派生クラスの種類が増えてくると、 この方法はコーディング量が非常に増えて 非効率的です。 プログラム上も美しくありません。 できれば、 同じクラスなのですから、 for(i=0;i<1000;i++){ if(A[i] == 100){...} } のような形で一括して検索するようにしたいのです。 つまり1つの配列変数で 両方を扱えるようにしたいのです。 ただし、当該IDを持つ、ポインタさえ取得できれば、 それぞれの派生クラスに型キャストしてから 操作するつもりです。 target = (classA-2)A[5]; target.Action(); どなたか、参考URL、キーワード、アドバイス等 頂ければ助かります。 よろしくお願いします。 よろしくお願いします。 としており、効率的ではなくなってしまいます。

  • javaの掲示板について

    今現在パスワードを比較して一致していれば削除としたのですがjava.sql.SQLException: Can not issue data manipulation statements with executeQuery().というエラーがtomcatにでます。 サーブレットはこう書いています //削除 if(deleteMessage != null){ String deleteid = request.getParameter("id"); String deletepassword = request.getParameter("deletepassword"); String rspassword = dao.getPassword(deleteid); if (deletepassword.equals(rspassword)){ dao.deleteMessage(delete); success = "削除しました。"; request.setAttribute("success", success); } else{ errorpass = "パスワードが違います。"; request.setAttribute("errorpass", errorpass); } } 比較用のパスワードをデータベースから取り出すDAOはこうしています。 public int deleteMessage(String strid) throws Exception { Vector messageList = new Vector(); int i = 0; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try{ conn = this.getConnection(); String sql = "delete from MESSAGE_TABLE where ID = ? "; pstmt = conn.prepareStatement(sql); pstmt.setString(1, strid); rs = pstmt.executeUpdate(); } finally { this.close(rs); this.close(pstmt); this.close(conn); } return i; } public String getPassword(String id) throws Exception { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; String rspassword = null; try { String deleteid = null; conn = this.getConnection(); String sql = "SELECT * FROM MESSAGE_TABLE where ID = ? "; pstmt = conn.prepareStatement(sql); pstmt.setString(1, id); rs = pstmt.executeQuery(); if(rs.next()){ rspassword = rs.getString("PASSWORD"); } } finally { this.close(rs); this.close(pstmt); this.close(conn); } return rspassword; } データベースからパスワードがとれていないから起きているのだとは思うのですが、どのようにしたらとれるでしょうか? よろしくお願いします。

    • ベストアンサー
    • Java
  • javaのスレッドの割込みについて

    javaのスレッド割込みに関する初心者の質問です。 割込みの発生元でCNTに値を設定し、割込みの受信元でCNTの値を読込み、表示しています。 下記のコードを参照ください。 Q1)CNTの値の設定と読込みで競合が発生する様なことはありませんか? 又は、処理が停滞するとか 以上、お手数をお掛けしますが、宜しくお願いします。 //割り込を発生するスレッド class threadA extends base{ private Thread target; public threadA(Thread targetA){ target = targetA; } public void run(){ for(int i = 0; i < 8;i++){ try{ System.out.print("."); Thread.sleep(1); CNT=i; target.interrupt(); }catch(InterruptedException e){ System.out.println("今割り込まれました: thread"); } } } } //スレッドからの割り込みを受信するルーチン class Sample108{ public static void main(String args[]){ //for(int i=0; i<2; i++){ classA obj = new classA(); obj.threadStart();//割り込みを受けるルーチン、この中で、割り込みを発生するルーチンを起動している //} } } //割り込みを受けるルーチン class classA extends base{ void threadStart(){ System.out.println("Start: main****"); threadA obj = new threadA(Thread.currentThread()); obj.start(); //Thread起動 //mainのルーチン for(int j = 0;j < 20; j++){ try{ Thread.sleep(1); System.out.print("*"); }catch(InterruptedException e){ System.out.println("今割り込まれました: classA CNT="+CNT); } } } } 以上

    • ベストアンサー
    • Java
  • for文についての質問

    for文についての質問 いつもお世話になっております。 本日はfor文のループについて確認したい事があり質問させて頂きます。 public class SearchAction extends DispatchAction { /** ロガー定義 */ private Log log = LogFactory.getLog(this.getClass()); public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // 開始ログ log.trace("[START]" + request.getSession().getId()); SearchForm sForm = (SearchForm) form; DataSource ds = getDataSource(request); Connection conn = null; sForm.initialize(); try { conn = ds.getConnection(); ServletContext sc = getServlet().getServletContext(); // 路線リストを取得し、アプリケーションスコープに格納 RosenBean rb = RosenBean.getInstance(); rb.load(conn); rb.loadToApp(sc); // INT xにサイズ分の数字を代入 int x = rb.size(); // サイズ分の箱を用意 LabelValueBean[] rosenList = new LabelValueBean[x]; // サイズ分ループ処理 for (int i = 0; i <= rb.size(); i++) { //System.out.println((LabelValueBean) rb.get(i)); rosenList[i] = (LabelValueBean) rb.get(i); System.out.println(rosenList[i]); System.out.println(i); sForm.setRosenList(rosenList); System.out.println(sForm.getRosenList()); } System.out.println("ここが通らない"); // 条件リストを取得し、アプリケーションスコープに格納 OtherBean ob = OtherBean.getInstance(); ob.load(conn); ob.loadToApp(sc);            } finally { if (conn != null) try { conn.close(); System.out.println("コネクションを閉じてみます"); } catch (Exception e) { System.out.println("例外内容" + e.getMessage()); } finally { conn = null; } 上記のソースについてですが、for文で処理を終えた後のSysoutが表示されずそれ以下の 処理が行われないので困っております。 しかし、それ以降のfinallyの中のSysoutは表示され(これは当たり前だと思いますが) なぜかfor文を終えた後にfinallyまで処理が飛んでるように思うのですが、これはなぜなんでしょうか 教えて頂ければ幸いです。 宜しくお願い致します。

    • ベストアンサー
    • Java
  • DB2の更新ロックについて

    DB2 v7を使用しています。 select文で更新ロックをかけました。 PreparedStatementとresultsetをcloseした後、同Connectionでupdate文をかけました。 このとき、select文のロックがかかってるのかわかりませんが、エラーも出ずに更新ができませんでした。 更新ロックのかけ方は 普通のselect文の最後に for updateとしただけです。updateは普通にupdateを行いました。 現在の状況としては、更新ロックがかかっているのかどうかわからないという状態です。 そこで、 (1)更新ロックがかかっているのかどうかを調べる方法があれば、その方法が知りたい。 (2)更新ロックの解除の方法をしりたい。 (3)select文で更新ロックをかけた場合の特別なupdateの方法が、その方法をしりたい。 どなたかご存知のかたがいらっしゃいましたらご教授くださいますようよろしくお願いいたします。 win2000 jdk1.3

  • 最大オープン・カーソル数のエラー

    javaサーブレットと、Oracle8iを使って、 C/S系のシステム開発をしています。 Javaサーブレットで、JDBCを使用してOracleへ接続しているのですが、 時々、以下のような、エラーが発生します。 Java.sql.SQLException: ORA-01000: 最大オープン・カーソル数を超えました。 原因は、何でしょうか? 最大オープン・カーソル数の個数を調べるには、どこを見ればいいのでしょうか? 是非ご教授下さい。

    • ベストアンサー
    • Java
  • PL/SQLについての質問です。

    PL/SQLについての質問です。 カーソルデータ(emp_rec(i))を、TABLE変数(emp_ins(i))に代入して、代入されたTABLE変数を使用して、DML処理を行うことは可能ですか? エラーを解読し対処を行っても、エラーが発生してしまいます。 どうか、ご教授お願いします。 下記を実行すると、下記エラーが発生します。 -実行結果------------------------------------ DECLARE * 行1でエラーが発生しました。: ORA-06502: PL/SQL: 数値または値のエラーが発生しました ORA-06512: 行127 -エラー番号解読----------------------------------------- ●エラー名: PL/ SQL: 数値または値のエラーstring が発生しました ●原因: 算術、数値、文字列、変換または制約エラーが発生しました。たとえば、NULL 値をNOT NULL で宣言した変数に割り当てようとした場合、または100 以上の整数をNUMBER( 2) で宣言した変数に割り当てようとした場合にこのエラーが発生します ●処置:値が制約違反をしないように、データ、操作方法または宣言方法を変更してください。 -ソース------------------------------------ DECLARE --カーソル定義 CURSOR emp_cur IS SELECT a,b,c FROM emp TYPE emptabtype IS TABLE OF emp%ROWTYPE INDEX BY PLS_INTEGER; emp_rec emptabtype; /* 処理対象データ格納変数 */ -- insert作業用 emp_ins emptabtype; ins_count NUMBER := 1; BEGIN /* empカーソルオープン・フェッチ・クローズ */ OPEN emp_cur; FETCH emp_cur BULK COLLECT INTO emp_rec; CLOSE emp_cur; /* (挿入)処理対象のデータを、処理対象データ格納変数に格納する。 */ FOR i IN emp_rec.FIRST..emp_rec.LAST LOOP --挿入するレコードを格納 emp_ins(ins_count) := emp_rec(i); ins_count := ins_count + 1; END LOOP; /* DML処理 */ -- 挿入する FOR count_ins IN emp_ins.FIRST..emp_ins.LAST LOOP INSERT INTO temp VALUES(emp_ins(count_ins).a ,emp_ins(count_ins).b ,emp_ins(count_ins).c); END LOOP; COMMIT; END; /