WEB相談室

Webページ作成に関しての何でも掲示板です。

タイトル:JSPで更新ボタン押下時、2回実行される?

0:[投稿] 和田 [2003/11/27 11:17 ][環境:Netscape4.73 WinNT,j2sdk1.4,Apache1.3,Tomcat4.0]

はじめまして。サーブレット・JSPを使用してWEBアプリを作成し始め、
半年になります。

JSPで作成したフォームで、項目を入力後、更新ボタンをおすと、サーブレットで
データベース(ACCESS)更新処理をおこないますが、追加更新のとき、

  「インデックス・主キーで値が重複するためテーブルへの変更は
   できませんでした」
というエラーがログに表示されます。

ところが、更新しようとしたデータは正しく保存されています。
そのため、フォームより2度Submitされているのではないかと
思っています。
また、この現象は必ずではなく、たまに(100更新中1回程度)起こります。

どこかのホームページで、HTMLの更新ボタンをimageにして、同時にonclic等の
Javascriptを使用すると、たまに2回Submitされる不具合があるという
記事はみかけましたが、このフォームの場合、submitボタンを使用しています。

下記に、Jspと更新処理(java bean)を抜粋しております。
Jspの問題か、またサーブレット・bean側の問題かはっきりしないのですが、
回答おまちしていますm(_ _)m

--------JSP------------
<%@ page contentType="text/html; charset=Shift_JIS" %>
<%@ page import="java.util.*" %>
<jsp:useBean id="userInfo" class="KintaiApp.UserInfo" scope="session" />
<jsp:useBean id="kintaiDT" class="Vector" scope="request" />

<HTML>
<HEAD>
<TITLE>管理</TITLE>
<LINK REL="stylesheet" TYPE="text/css" HREF="/kintai/KintaiApp/basic.css">
<SCRIPT LANGUAGE="JavaScript">
<!--
}
/** 更新前チェック **/
function subChk(ivalue){
 if(document.forms[0].Syukin.checked && document.forms[0].Kaia.value>0){
         alert("エラー!");
         document.HiUpdDB.Syukin.focus();
         a = false;
 }

//状況チェック
 if(ivalue==2)
      var b = confirm("更新しますか?");
//結果
 var c = a
 if(a==true && b==false)
     c = b;
 return c;
}
//-->
<BODY>

 〜タイトル表示

<FORM NAME="HiUpdDB" METHOD="POST" onSubmit="return subChk(<%=jokyo %>)" ACTION="/kintai/servlet/KServlet">
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="5">
<TR CLASS="aquagray"><TD>

<!--   入力欄 表示開始 -->
<TABLE BORDER="1" CELLSPACING="5" CELLPADDING="2" WIDTH="565">
<TR>
 <TD ALIGN="left" COLSPAN="3"><TT>
   時間外:<INPUT TYPE="text" NAME="Jgai" VALUE="<%=s.getJgai() %>" SIZE="6" onBlur="numChk(this.value, this.name)" onFocus="document.HiUpdDB.Jgai.select()">
   &nbsp;非割増時間:<INPUT TYPE="text" NAME="Hiwa" VALUE="<%=s.getHiwa() %>" SIZE="6" onChange="numChk(this.value, this.name)" onFocus="document.HiUpdDB.Hiwa.select()">
   &nbsp;深夜時間:<INPUT TYPE="text" NAME="Siny" VALUE="<%=s.getSiny() %>" SIZE="6" onChange="numChk(this.value, this.name)" onFocus="document.HiUpdDB.Siny.select()">
   &nbsp;買上時間:<INPUT TYPE="text" NAME="Kaia" VALUE="<%=s.getKaia() %>" SIZE="6" onChange="numChk(this.value, this.name)" onFocus="document.HiUpdDB.Kaia.select()">

 〜他入力項目

</TR>
</TABLE>

<!--   フッター 表示開始 -->
<TR CLASS="yellowgray">
 <TD ALIGN="right">
   <INPUT TYPE="submit" NAME="HiUpd" VALUE="更新">
  &nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="reset" VALUE="リセット">
 </TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML>
</HEAD>

------更新処理(java bean)-------
 public static boolean dbupd2(CalInfo inCalInfo, String inSelscord[],
     int inKinmu[], int inSyukin[], long inSyukinId[],
     double inJgai[], long inJgaiId[], double inHiwa[], long inHiwaId[],
     double inSiny[], long inSinyId[], double inKaia[], long inKaiaId[],
     int inKyujitu[], long inKyujituId[]) {

     //更新氏名コード数
     int num = inSelscord.length;

     //登録
     DBConnect dbConnect = null;
     Connection conn = null;
     Statement stmt = null;
     Statement ss = null;
     ResultSet rst = null;
     String qryStr;
     qryStr = "";

     try {
         long inKyymm = inCalInfo.getKyymm();
         int inYear = inCalInfo.getYear();
         int inMonth = inCalInfo.getMonth();
         int inDay = inCalInfo.getDay();

         //データベース接続
         dbConnect = DBConnect.getInstance();
         conn = dbConnect.Connect();
         stmt = conn.createStatement();

       //データベースの更新
       for(int i=0; i<num; i++){  
         //------出勤・勤務--------------------------------------
         if(inSyukinId[i] != 0) {  //更新
               qryStr = "UPDATE Syukin_T SET Naiyo=" + inSyukin[i] + ", Kinmu=" + inKinmu[i];
               qryStr += ", Jchk=0";
               qryStr += " WHERE ((id=" + inSyukinId[i] + ")";
               qryStr += " AND ((Naiyo<>" + inSyukin[i] + ") OR (Kinmu<>" + inKinmu[i] + ")))";
               stmt.executeUpdate(qryStr);
         } else {                  //追加
            if(inSyukin[i] != 0 || inKinmu[i] != 0) {
               qryStr = "INSERT INTO Syukin_T ( Kyymm, yy, mm, dd, Scord, Naiyo, Kinmu )";
               qryStr += " SELECT " + inKyymm + ", "+ inYear + ", " + inMonth + "," + inDay + ",";
               qryStr += " '" + inSelscord[i] + "', " + inSyukin[i] + ", " + inKinmu[i] + ";";
               stmt.executeUpdate(qryStr);
            }
         }      
         //------時間外------------------------------------------
         if(inJgaiId[i] != 0) {   //更新
               qryStr = "UPDATE Jikan_T SET Naiyo=" + inJgai[i];
               qryStr += ", Jchk=0";
               qryStr += " WHERE ((id=" + inJgaiId[i] + ") AND (Naiyo<>" + inJgai[i] + "));";
               stmt.executeUpdate(qryStr);
         } else {                 //追加
            if(inJgai[i] != 0) {
               qryStr = "INSERT INTO Jikan_T ( Kyymm, yy, mm, dd, Scord, Cd, Naiyo )";
               qryStr += " SELECT " + inKyymm + ", "+ inYear + ", " + inMonth + ",";
               qryStr += " " + inDay + ", '" + inSelscord[i] + "', 1, " + inJgai[i] + ";";
               stmt.executeUpdate(qryStr);
            }
         }      
 〜他更新処理
       }
         //正常終了
         stmt.close();
         dbConnect.Disconnect(conn);
         return true;

     } catch(SQLException se) {
         //後始末
         try {
             do {
               System.err.println("SQLSTATE: " + se.getSQLState());
               System.err.println("ERR-CODE: " + se.getErrorCode());
               System.err.println("ERR-MSEG: " + se.getMessage());
               System.err.println("ERR-PG1: DBData.dbupd2  qryStr: " + qryStr);
               se = se.getNextException();
             } while (null != se);      // SQLExceptionリストの最後までループする.
             if(stmt != null) stmt.close();
             if(conn != null) dbConnect.Disconnect(conn);
         } catch(SQLException se2) {
             //取り敢えず何もしない
             do {
               System.err.println("SQLSTATE: " + se2.getSQLState());
               System.err.println("ERR-CODE: " + se2.getErrorCode());
               System.err.println("ERR-MSEG: " + se2.getMessage());
               System.err.println("ERR-PG2: DBData.dbupd2  qryStr: " + qryStr);
               se2 = se2.getNextException();
             } while (null != se2);      // SQLExceptionリストの最後までループする.
             
         }
         return false;
}}}

-------- エラーログ ---------
ERR-MSEG:[Microsoft][ODBC Microsoft Access97ドライバ]更新可能なクエリーでなければなりません。
ERR-PG1:DBData.dbupd qryStr: INSERT INTO Syukin_T(Kyymm,yy,mm,dd,Scord,
Naiyo,Kinmu) SELECT 200311,2003,10,28,'T1111',1,5;


1:[回答] 岩本隆史 [MAIL] [URL] [2003/12/02 12:13 ]

2度submitされるのを防ぐ方法ですが、subChk関数がtrueを返す直前にボタンをdisabledにしてしまうのはいかがでしょうか。

ただ、仮に2度submitされているとして、その場合にはレコードが2件作成されるのが正常な動作ではないでしょうか。追加更新処理のロジックを見直す必要があるように思われます。


2:[回答] AC [2003/12/02 21:02 ]

関係があるのかどうかは分からないが、
・script要素の終了タグがない
・head要素の終了タグが変な場所にある

>>1
更新対象のテーブルにunique制約をつけているのであれば、
同じレコードを作ろうとすれば一意制約違反になるのは正しい動作です。


3:[回答] 岩本隆史 [MAIL] [URL] [2003/12/03 00:20 ]

> 更新対象のテーブルにunique制約をつけているのであれば、
> 同じレコードを作ろうとすれば一意制約違反になるのは正しい動作です。

ご指摘ありがとうございます。
「id」フィールド(オートナンバー型)があるので、他のフィールドにunique制約を設定している可能性を考慮しておりませんでした。


4:[完了] 和田 [2003/12/08 15:20 ]

ご意見ありがとうございます_(._.)_。もう回答がないとあきらめておりました。


>関係があるのかどうかは分からないが、
>        ・script要素の終了タグがない
>        ・head要素の終了タグが変な場所にある

上記、チェックしましたが、あわてて質問文章をつくったため、
はりつけがおかしくなっていました。実際は、正しく書いているため
関係ないとおもうのですが。。。

>2度submitされるのを防ぐ方法ですが、subChk関数がtrueを返す直前にボタンをdisabledにしてしまうのはいかがでしょうか。

上記、試してみたいと思います。

回答(必須): 状態:

お名前(必須):

e-mail:

URL:




[戻る]

ChaichanPAPA's World