ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Java質問&情報提供サイトコミュのJSPで質問です。

  • mixiチェック
  • このエントリーをはてなブックマークに追加
はじめましてバシです。

フォームからSQLのコマンド
例:SELECT * fruit;
を入力してJSPに表示させたいんですが、なぜだか以下のようなエラーがでてしまいます。(ブラウザーの中にエラーがでます。)
注意)フォームから入力したSELECT文は実行できます。

エラー:java.sql.SQLException: Operation not allowed after ResultSet closed at

説明が苦手なので写真を添付しました。

JSPとMySQLの接続でどこがうまくいっていないために出ていると思うのですが原因がわかりません。
よろしくお願いします。

ブラウザーのエラーのところを出さない方法がわかる方ご教授よろしくお願いいたします。
<%@ page contentType="text/html; charset=UTF-8" import="java.sql.*,java.io.*" %>
<html>
<head><title>MySQLとの接続</title></head>
<body>
<h3>テーブルfruit</h3>

<form method="POST" action="mysql.jsp">
SQL文:<input type="text" name="form_name" size="40" />
<input type = "submit" value="実行" />
</form>

<hr>

<%

if( request.getParameter("form_name") !=null){
Connection con = null;
Statement stmt = null;
String url =
"jdbc:mysql://localhost/dbunknow?useUnicode=true&characterEncoding=UTF-8";
String user = "unknow";
String passwd = "shitumon";
try {
Class.forName("org.gjt.mm.mysql.Driver"); //おまじない
con = DriverManager.getConnection(url, user, passwd);//MySQLに接続
stmt = con.createStatement(); //SQL発行の準備

request.setCharacterEncoding("UTF-8");//文字化け防止措置
String sql = request.getParameter("form_name");
ResultSet rs = stmt.executeQuery(sql);

if(request.getParameter("form_name") !=null){
out.print("<table border=1>");
while (rs.next()) { //結果の件数だけ繰り返す
String name = rs.getString("item"); //フィールドitemの取得
int price = rs.getInt("price"); //フィールドpriceの取得
int weight = rs.getInt("weight");

out.print("<tr>"+"<td>"+"品名"+"</td>");
out.print("<td>"+"値段"+"</td>");
out.print("<td>"+"重さ"+"</td>"+"</tr>");

out.print("<tr>"+"<td>"+(name)+"</td>");
out.print("<td>"+(price)+"</td>");
out.print("<td>"+(weight)+"</td>"+"</tr>");
}
out.print("</table>");
}
stmt.close(); //終了処理
con.close(); //終了処理

} catch (Exception e) {
e.printStackTrace(new PrintWriter(out));
} finally {
try { stmt.close(); con.close(); } catch(Exception e) {}
}
}
%>


</body>
</html>

コメント(34)

finallyでclose処理をしているのに事前に

stmt.close(); //終了処理
con.close(); //終了処理

としているのを取りましょう。
それで解決すると思いますが、念のためくどく

try { stmt.close(); con.close(); } catch(Exception e) {}



if(rs!=null){try{rs.close();} catch(Exception e) {e.printStackTrace();}}
if(stmst!=null){try{stmt.close();} catch(Exception e) {e.printStackTrace();}}
if(con!=null){try{con.close();} catch(Exception e) {e.printStackTrace();}}

とした方が、catchへのこだわりとしては
よいのかもしれません。
はじめましてTriaxisです。

>ブラウザーのエラーのところを出さない方法がわかる方ご教授よろしくお願いいたします。
} catch (Exception e) {
e.printStackTrace(new PrintWriter(out));

となっているので、スタックトレースをブラウザに送ってしまっていると思います。

エラーについては、Operation not allowed(next()あたり)が出ているようなので、
>while (rs.next()) { //結果の件数だけ繰り返す
が怪しいと思います。

・・突っ込み所が満載ですが、とりあえずがんばってください。
>きよさん

stmt.close(); //終了処理
con.close(); //終了処理
を消したらブラウザーのエラーはきえまた。ありがとうございました。

何もフォームにないとき実行を押すとまた画像のようなエラーがでてしまいました。

>Triaxisさん
>while (rs.next())ここの部分が怪しいんですか!!考えて見ます。

初心者です。色々と突っ込んでください><;
現状のプログラムではフォームが空の場合は
空文字をSQLとして実行しようとするので
エラーが出るのは当然だと思います。

適時入力チェックを行ってください。
>きよさん
if(request.getParameter("form_name") !=null && request.getParameter("form_name") !="''" )

空文字は''でいいんですよね?

if文を追加してみましたが、やはり空文字が入ってしまいます。空文字=0文字の文字列なのでしょうか?

よろしくお願いします。
文字列の比較は、String#equalsを使います。
空文字は""です。
>ykhrさん

空文字の比較はその関数を使うんですか^^;

アドバイスありがとうございます。
String a='';
a.equals(a2)
''.equals(a)
a.equals('')

こんな感じでいのでしょうか?いまいちつかめていません。

空文字と空文字を比較して、それが空文字だったら実行しない、見たいにすればいいのでしょうか?^^;

ご教授よろしくお願いします。
Stringはダブルクォーテーションで囲みます。
↓のサンプルはtrueになります。
String str = "";
if ("".equals(str)) {
  System.out.println(true);
} else {
  System.out.println(false);
}

> 空文字と空文字を比較して、それが空文字だったら実行しない、見たいにすればいいのでしょうか?^^;

requestから取得した文字列と空文字を比較して
trueだったら実行しないようにすればよいはずです。
5のrequest.getParameter("form_name") !="''"の部分を
少し変えればできるはずですよ。
空文字判定なら

String sql = request.getParameter("form_name");
if(sql!=null||!"".equals(sql)){
//SQLの実行
}
}

でよいでしょうが、今回はSQLなので

String sql = request.getParameter("form_name");
if(sql!=null||!"".equals(sql)){
sql = sql.toLowerCase();
if(sql.indexOf("select")>0||sql.indexOf("update")>0||sql.indexOf("delete")>0){
//SQLの実行
}
}

くらいはしてはどうでしょうか。
> きよさん
まぁ実際はそうなんですが、SQLなんて完璧にチェックするのは不可能なので
空文字チェックだけでもいいかなーと。
ここらへんはバシさんのやりたいようにすればいいのかな。

また、きよさんのソースについてですが、indexOfの判定は>=0じゃないですか?
もしくは、indexOfじゃなくてもtrimしてstartsWithでいいのかも。

ちなみにexecuteQueryってSELECT文以外実行できましたっけ?
>ykhrさん
そういえばINSERT/UPDATE/DELETEはexecuteUpdateでしたね、
10のソースは不完全なので真似しないで下さい>バシさん
>きよさん
String sql = request.getParameter("form_name");
この後にifを書くとwhile (rs.next()) {の部分にエラーがありますと表示されてしまいif文を使うことができません。どうしたらいいでしょうか?
ResultSet rs = stmt.executeQuery(sql);

>ykhrさん

(str !="");

こんな感じにすればいいのでしょうか?
> きよさん
手元にあったHSQLDBでやったらINSERT/UPDATE/DELETEすべて
通っちゃいました(汗
しかもResultSet#nextはfalseになりました。

他のDBは出来ないかもしんないですけど、
こんなこともあるんですねぇ。

> とおるさん
すみません、試しちゃいました。
しょせんはJDBCドライバの実装依存ですかね。

スレ違いでごめんなさい。
> バシさん
文字列の比較は7と9に書いた通りですよ。
空文字でないことのチェックは、こんな感じになります。
if (!"".equals(sql))
あと、チェックはSQL実行前にやってください。

また、エラーというのはどっかしらに構文的な間違いがあるからでは?
ifが書けないなんてことはないはず。


今更ながら、空文字のチェックはString#lengthを使ってももいいのかも。
自己レスです。
> 文字列の比較は7と9に書いた通りですよ。
すみません、6と9でした。
> べジータさん
SQLの実行自体は、3でできてると思いますよ。
closeについても、1できよさんが指摘されてます。
ただ、フォームに何も入れなかったらエラーになったということへの対処から
せめて簡単な入力チェックくらい・・・といって進んだ話です。


と思ってたんですが、SQLは実行できたんですよね?
>とおるさん
finally句でcloseしたいのですが、try { stmt.close(); con.close(); rs.close();}と書くとエラーになってしまいます。
>ykhrさん
System.out.println(true); この文なんですが使いかたが本にのってなくてわからないです^^;

追記情報:OSはSUSEです。DBはMySQLです。参考書は「はじめてのJSP&サーブレット プログラミング」著者:アイティーブースト 発行:秀和システム です。

始めの表示のときのsql文のエラーはなくなりました。
正しいSELECT文を実行させたときに表れていたsql文のエラーもなくなりました。
後は何も入れない(空文字の)時、エラーがやはりでてしまいます。
以下の部分をifで囲んできよさんの空文字判定を書いてみましたがエラーでした。
ResultSet rs = stmt.executeQuery(sql);

どこか根本的に間違っているのでしょうか?^^;

改変後のソースです。
<%@ page contentType="text/html; charset=UTF-8" import="java.sql.*,java.io.*" %>
<html>
<head><title>MySQLとの接続</title></head>
<body>
<h3>テーブルfruit</h3>

<form method="POST" action="mysql.jsp">
SQL文:<input type="text" name="form_name" size="40" />
<input type = "submit" value="実行" />
</form>


<hr>

<%
if(request.getParameter("form_name")!=null && request.getParameter("form_name") !="" ){

Connection con = null;
Statement stmt = null;
String url = "jdbc:mysql://localhost/dbunknow?useUnicode=true&characterEncoding=UTF-8";
String user = "unknow";
String passwd = "shitumon";

try {
Class.forName("org.gjt.mm.mysql.Driver"); //おまじない
con = DriverManager.getConnection(url, user, passwd);//MySQLに接続
stmt = con.createStatement(); //SQL発行の準備

request.setCharacterEncoding("UTF-8");//文字化け防止措置
String sql =request.getParameter("form_name");
ResultSet rs = stmt.executeQuery(sql);

out.print("<table border=1>");
while (rs.next()) { //結果の件数だけ繰り返す
String name = rs.getString("item"); //フィールドitemの取得
int price = rs.getInt("price"); //フィールドpriceの取得
int weight = rs.getInt("weight");

out.print("<tr>"+"<td>"+"品名"+"</td>");
out.print("<td>"+"値段"+"</td>");
out.print("<td>"+"重さ"+"</td>"+"</tr>");

out.print("<tr>"+"<td>"+(name)+"</td>");
out.print("<td>"+(price)+"</td>");
out.print("<td>"+(weight)+"</td>"+"</tr>");
}
out.print("</table>");

} catch (Exception e) {
e.printStackTrace(new PrintWriter(out));
} finally {
try { stmt.close(); con.close();} catch(Exception e) {}
}

}
%>

</body>
</html>
>ykhrさん
本当にすいません><;
if文の括弧の位置が違う文の括弧として扱われていたみたいで、それがエラーの原因になっていました。本当に申し訳ありません^^;

if (sql!=null && !"".equals(sql)){
ばっちりエラーがでなくなりました。


ykhrさん、JSPとMySQLでよい参考書を知っていました教えていただけないでしょうか?お願いします。

>ベジータさん
>Finally句でのCloseですが、SQLが正常に成功しCloseしてるの>にもう1回FinallyでCloseするとSQLExceptionが出る可能性>がありますので、NULL判定をしてからCloseするといいと思います。

参考になります。ありがとうございました。

きよさん、Triaxisさん、ykhrさん、とおるさん、ベジータさんわかりやすいアドバイスありがとうございました。
System.out.println(true);は空文字チェックの動きを
示すためのサンプルなんで、JSPとはまったく関係ないです。
わかりにくくて申し訳ないです。

finally句でrs.close()を書くとエラーとなるのは、
変数rsの宣言がtry内にあるからではないですかね。

本に関しては、私はJSP・Servlet関連の本を持っていないので
なんとも言えないです。ただ、私が本を買う際は、周りの人や
amazonのレビューなんかを参考にして選ぶことが多いです。
ただ、バシさんはJSP・Servletの前にJavaの本を読んだほうが
いいかなーと思います。
>ykhrさん

そおいうサンプルだったんですか!わからなくてすいませんでした^^;

JSPよりJavaの方が難しいと思い、JSPの入門書を買ってしまいました^^;

これからもよろしくお願いしますm(_ _)m
すいませんふと思ったのですが、SELECT文以外の文字がフォームに入力されたときに実行を押すとエラーになるのと思い、今やってみたらエラーでした;;

多くのSELCET文をifで書いて条件分岐させなければこの問題は回避できないのでしょうか?

お分かりに方がいらっしゃいましたらご教授よろしくお願いいたします。
>24

質問の意味がわかりません。
入力フォームから取得したqueryを投げるプログラムだから、構文が間違っていたらエラーになるのは当たり前の動作では?

もうちょっと具体的にやりたい事を書いた方が良いと思います。
> if(request.getParameter("form_name")!=null && request.getParameter("form_name") !="" ){

まず、質問内容とは関係ないですが、上記は、
if(request.getParameter("form_name")!=null && !request.getParameter("form_name").equals("") ){
に修正した方が良いでしょう。
Javaでの文字列は、equals()メソッドを使うが吉です。

んで、

>すいませんふと思ったのですが、SELECT文以外の文字がフォームに入力されたときに実行を押すとエラーになるのと思い、今やってみたらエラーでした;;
>多くのSELCET文をifで書いて条件分岐させなければこの問題は回避できないのでしょうか?

上記は、Select文以外の文字って何のことでしょうか。ちと分かりかねます。
Insert文やUpdate文を発行したときの場合でしたら、
SQL実行後、必ず結果セットがある前提で、ResultSetのループを回しているため、エラーになるのは必然かと。
UPDATEやINSERT文の実行結果は、変更が行われた行数ですので・・・
(SELECT文発行時とINSERT・UPDATE文発行時の違いは少し調べるとわんさか出てくるのでGoogle先生とお友達になってください)

汎用的に使用するなら、ResultSetMetadataを利用しましょう。
上記インターフェースを利用して取得してきた結果セットのカラムタイプ(文字型とか数値型とか)や、
カラム名称がわかります。
サンプルコードだと、
"item"、
"price"、
"weight"
の三つのカラムを持っていないテーブルを検索した場合、よくわからんことになると思います。

まぁ、色々試してみてくださいな。
>名無し猫さん
詳しくいうとですね、正しいSELECT文を入力して実行のボタンを押すとsqlコマンドが実行されてそれに対応した結果が返ってきます。

正しいコマンド
SELECT * FROM fruit;

結果の例
画像1

しかし間違ったSELECT文を入力したとき(後ろのセミコロンを忘れたetc...)に実行を押すとsqlのエラーが表示されてしまうのです。

コマンド例
SELECT * FROM fruitなど(入力ミス)

結果の例
画像2

これを回避する方法はないのでしょうか?という質問でした。^^;

正しいセレクト文以外はエラーを表示したいのです。

>SYK@しゃらくさーい!
>Javaでの文字列は、equals()メソッドを使うが吉です。

とても参考になりますありがとうございました。
>バシさん
RUBYでは、構文解析してエラーチェックできると言う話を聞いていますが、JAVAで出来ると言う話は残念ながら私は知りません。

解決にはならないかも知れませんが、SQLExceptionが発生した場合にカスタムエラーページに飛ばす方法があります。

<
%@ page contentType="text/html; charset=UTF-8" import="java.sql.*,java.io.*" errorPage="/error_page.jsp" %>


errorPage="/error_page.jsp"の様に追加すると、内部エラー発生時にerror_page.jspへ飛ばすことができます。
error_page.jspで、表示したい内容の画面を作成できます。

++ error_page.jsp ++

<%@ page isErrorPage="true" contentType="text/html; charset=UTF-8" %>
<html>
<head>
<title>エラー</title>
</head>
<body>
次のようなエラーが発生しました。
<b><%=exception%>が発生しました。</b><br>
</body>
</html>

+++++++

参考:@IT
http://www.atmarkit.co.jp/fjava/rensai/jsp2_04/jsp2_04_1.html


注意する点は以下の通りです。
・catchした後throwし直す必要性がある。
・finallyで別のExceptionが発生すると書きつぶしてしまう
・すべての内部エラーをカスタムエラーページに飛ばしてしまう

色々注意点があるのですが、JSPというよりJavaに絡む要素です。
結局、Javaの知識は必要ですよ。

あまり、期待に添えられなくてすいません。
>名無し猫さん

JAVAではそういうのがないんですか^^;とても参考になりました。
ページを飛ばす方法なのですが、以下の用にしてみたのですが、エラー時に飛ばないのですが、何かifの条件式を書く必要があるのでしょうか?

引き続きよろしくお願いします。

//mysql.jsp
<%@ page contentType="text/html; charset=UTF-8" import="java.sql.*,java.io.*" errorPage="/error_page.jsp" %>
<html>
<head><title>MySQLとの接続</title></head>
<body>
<h3>テーブルfruit</h3>

<form method="POST" action="mysql.jsp">
SQL文:<input type="text" name="form_name" size="40" />
<input type = "submit" value="実行" />
</form>


<hr>

<%
if(request.getParameter("form_name")!=null && !request.getParameter("form_name") .equals("")){

Connection con = null;
Statement stmt = null;
String url = "jdbc:mysql://localhost/dbunknow?useUnicode=true&characterEncoding=UTF-8";
String user = "unknow";
String passwd = "shitumon";

try {
Class.forName("org.gjt.mm.mysql.Driver"); //おまじない
con = DriverManager.getConnection(url, user, passwd);//MySQLに接続
stmt = con.createStatement(); //SQL発行の準備

request.setCharacterEncoding("UTF-8");//文字化け防止措置
String sql =request.getParameter("form_name");

if (sql!=null && !"".equals(sql)){
ResultSet rs = stmt.executeQuery(sql);
out.print("<table border=1>");
while (rs.next()) { //結果の件数だけ繰り返す
String name = rs.getString("item"); //フィールドitemの取得
int price = rs.getInt("price"); //フィールドpriceの取得
int weight = rs.getInt("weight");

out.print("<tr>"+"<td>"+"品名"+"</td>");
out.print("<td>"+"値段"+"</td>");
out.print("<td>"+"重さ"+"</td>"+"</tr>");
out.print("<tr>"+"<td>"+(name)+"</td>");
out.print("<td>"+(price)+"</td>");
out.print("<td>"+(weight)+"</td>"+"</tr>");
}
out.print("</table>");

}

} catch (Exception e) {
e.printStackTrace(new PrintWriter(out));
} finally {
try { stmt.close(); con.close();} catch(Exception e) {}
}
}
%>

</body>
</html>


//error_page.jsp
<%@ page isErrorPage="true" contentType="text/html; charset=UTF-8" %>

<html>
<head>
<title>エラー</title>
</head>
<body>
次のようなエラーが発生しました。
<b><%=exception%>が発生しました。</b><br>
</body>
</html>
errorPageと記述するということが、どういう動作をすることなのか、また、try {} catch(Exception e) の記述がどういう動作をすることなのか をあわせれば、飛ばなくて当然なんですが・・・ひょっとして、紹介されたソースを、動作仕様も確認せずに手当たり次第に試しているのでしょうか?
というか、
>注意する点は以下の通りです。
>・catchした後throwし直す必要性がある。
>・finallyで別のExceptionが発生すると書きつぶしてしまう
>・すべての内部エラーをカスタムエラーページに飛ばしてしまう
と、調べなおすまでも無く発言内にもかかれてますね・・・

なお、JSPは、JAVAをhtmlに埋め込んでどうささせる方法であり、あくまでも、Javaという言語があって、そのうえで、htmlから簡単にまぜて(?)記述するための方法です。JSPを使う上では、Javaは前提知識となります。
# 自分でバグの調査まで考えると、Serveletの動作もわかってないとむつかしいです。結局、JSP→JavaServeletと変換されてから動作しますし。そういった意味では、JSPは、ただの(?)Java(JavaApplication)よりも、2段階(?)複雑 ということになります。
>ベジータさん

情報ありがとうございます。

>うぇいくさん

すいませんJSPをはじめてまだ日が浅いもので^^;

SQLとの連携はこれが始めてで、色々困惑しています。

正しいSELECT文 実行

SELECT分の命令通りの結果を表示

空文字の時がフォームにある時 実行

if条件でExceptionするのを防ぐ。

間違ったSELECT文やスペルミスの入力 実行

Exceptionが発生。回避方法は、Exceptionが発生したときは
エラー文の書いてあるページに飛ばして、正しい構文を入力
するような指示をする。

Javaの知識が前提条件に必要なんですか^^;参考書を見直してみます。
>バシさんへ
もうちょっと詳しく書くと…。
catchしちゃうとその中でエラー処理が終わっちゃうので、Exceptionを再度投げる(throwする)必要があります。

try
{
<<省略>>
} catch (Exception e) {
throw e;
} finally {
<<省略>>
}

ちなみにthrowしても必ずfinallyは実行されます。
このとき、finallyで別のExceptionが発生すると前に発生したExceptionの内容を上書きしちゃいます。
そうすると、errorPageで受け取った内容で意図しない処理をしてしまう可能性があります。

あと、教えられた知識を丸写しするのでは無く、その周辺の知識もgoogle先生辺りにお伺いを立てると良いと思われます。
今は情報がネット上に転がってますから、覚えることより理解することを心がけてください。
(極論から言えば、覚えて無くてもさほど問題はありません)

ついでに言えば、WEBアプリケーション(JSP等)はネットワーク、文字コード、データベース、Java言語、コンテナの仕様等の色々な知識が必要とされます。
まともなものを作ろうとすると、逆に覚えること多いですよ?
(まあ、今は猫も杓子もWEBアプリケーションですがw)
>名無し猫さん

sqlのところをもっと勉強したいと思います!!

理解するように心がけます!!

webは難しいんですね^^;

とても参考になりました!!

今後ともよろしくお願いします。

ログインすると、残り3件のコメントが見れるよ

mixiユーザー
ログインしてコメントしよう!

Java質問&情報提供サイト 更新情報

Java質問&情報提供サイトのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング