- ベストアンサー
サーブレット処理のキャンセル
はじめまして。 環境: apache2.052 + jk2(2.04) + tomcat5.028 質問: CSVファイルをアップロードして、DBに登録する業務があります。 CSVアップロード ↓ サーブレット:DB登録 ↓ 結果出力 DB登録の処理時間が20秒ほどかかるため、その間にブラウザを閉じたり、別のリンクをクリックされる場合があります(キャンセルの意を込めて?)。 そのような操作がされた場合、ユーザには登録の結果(エラーの有無等)を知る手段がないため、サーバ側のDB登録処理をキャンセル(ロールバック)させたいのですが、現状、ブラウザの状態にかかわらずDB登録処理は最後まで行われてしまいます。 なにかよい方法はございませんでしょうか。 また、一般的にはこのような処理は行わないものなのでしょうか。 よろしくお願いいたします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
>処理メニューなど、フレーム分割されている場合を >想定しておりました。 …orz そうですね。(^^;A まったく漏れてました。 申し訳ありませんでした。 前の現場ではフレームで共通に各ボタンに対するフラグを持ってて、レスポンスが返ってくるまでボタンが押されてもリクエストを飛ばさないように制御してましたね。 細かい部分でどうやって実現していたかは知りませんが…。 (ボタンがいっぱいあったのでフラグ設定ミスなどバグもそれなりにありましたが…他チームでよかったと思ってます。(笑))
その他の回答 (3)
- pcbeginner
- ベストアンサー率46% (261/560)
>DB登録の処理時間が20秒ほどかかるため、その間にブラウザを閉じたり、 >別のリンクをクリックされる場合があります(キャンセルの意を込めて?)。 「閉じたり」はわかりますが、サーブレット1本でやった場合に、他のリンクをクリックできます? あー、サーブレットでhtmlを直に吐いてれば、途中までは表示されるのかな…。わかんないけど…。 そうでなければ、ブラウザはずっと白い画面で「○○を開いてます。」って出ませんでしたっけ? >キャンセルする場合、ユーザ(ブラウザ)の状態を判断するにはセションが切れるのを待つしかないため セッションが切れるのはあくまでもセッションタイムアウトになった場合です。 セッションタイムアウトが起きたからといって、ブラウザが閉じられたとは限りません。ブラウザを開いたままでもセッションタイムアウトの設定値だけ放置しておけばセッションは切れます。 >セションが切れるとスレッドの状態がわからなくなる 確かにそのとおりですが、いちおうMETAタグで○秒おきにリクエストを飛ばすので大丈夫かなと。 ブラウザの「×」ボタンとかやられたら仕方ないですけど、そこはユーザーとの決め事で「やらないで下さい。」と言うしかないですね。 まぁそれでもやられた場合のことを考慮して、ログなど解析の元ネタはちゃんと出力しないといけませんね。 >今回のようなアップロード処理に限らず、サーブレット処理中にブラウザを閉じるとか、別のリンクをクリックするということは大いにありえますよね。 まぁそうなんですけど、でも、できることとできないことがあって、できることの中にも非常に面倒だったり、工数がかかることもあるので、そこは費用とかの兼ね合いでエンドユーザーさんには「やらないで下さい。」と決めないといけませんね。 (上でも述べましたが。) それがダメということならクライアントにブラウザを使わないで、他のものを使うなり、クライアントも開発をするなりしないとだめですね。 あとはなるべく「×」ボタンを押したくならないように工夫することですかね。 例えば -------------------------------------------------- 登録スレッドクラス ・セッションからファイル名を取得 ・登録結果「登録中:ファイル読み込み中」 ・登録結果「登録中:ファイル読み込み完了」 ・登録結果「登録中:DBに登録中」 ・DBに登録 ・登録結果「登録完了」 -------------------------------------------------- -------------------------------------------------- 登録中画面 ・METAタグを使って○秒おきにチェックするサーブレットに 要求を投げる ・登録中メッセージを表示 -------------------------------------------------- のようにして、 「動いてますよ!止まってませんよ!!」 ってことをアピールすれば「×」ボタンは押されにくくなるかもしれません。 >サーブレット処理はキャンセルされずに完走するのが通常ということなのでしょうか。 そうですね。 以上、長々と失礼しました。
- Bonjin
- ベストアンサー率43% (418/971)
>ユーザには登録の結果(エラーの有無等)を知る手段がないため、サーバ側のDB登録処理をキャンセル(ロールバック)させたいのですが、 というのなら、キャンセルさせる方法ではなく、結果を知る手段を考えるべきでは? そもそも、ブラウザの状態をWebサーバ側から知りたいという仕様が、Webシステムに向いていません。 キャンセルするにしろ、結果を取得するにしろ、サーブレットとは別にスレッドを起こして、そのスレッドを管理すればいいだけです。 しかし、キャンセルする場合、ユーザ(ブラウザ)の状態を判断するにはセションが切れるのを待つしかないため、DBにおいて長時間のロックが発生することになります。セションのタイムアウト時間を短くすれば別ですが、現実的ではありません。 私ならば、キャンセルする方法よりも、結果を取得できるような機構を実装することをお勧めします。 実装例については#1の方が書かれていますが、登録スレッドとセションを関連づけるのは良くありません(セションが切れるとスレッドの状態がわからなくなる)ので、もう少し考慮が必要です。
補足
pcbeginnerさん、Bonjinさんありがとうございます。 キャンセルするのは一般的ではないということなんですね。 私は、「ブラウザが閉じられた」ということは、サーブレットにとっては「出力先を失った」ということになって、(例えば以下のソースの)doGetメソッドのレスポンスを返すところでIOExceptionが発生して、それを契機にロールバック処理に移れるのでは?と考えていたのですが、どうやらブラウザを閉じてもIOExceptionは返らないようですね。 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html><body>Hello World!</body></html>"); out.close(); } そこでさらに疑問なのですが、今回のようなアップロード処理に限らず、サーブレット処理中にブラウザを閉じるとか、別のリンクをクリックするということは大いにありえますよね。 その場合もやはりサーブレット処理はキャンセルされずに完走するのが通常ということなのでしょうか。
- pcbeginner
- ベストアンサー率46% (261/560)
一般的かどうかは分かりませんが、 サーブレット ・受信したファイルをテンポラリディレクトリに保存 ・セッションにファイル名などをセット ・セッションに登録結果を「登録中」でセット ・登録スレッドクラス.start() ・チェックするサーブレットにフォワード 登録スレッドクラス ・セッションからファイル名を取得 ・DBに登録 ・登録結果をセッションにセット チェックするサーブレット ・セッションから登録結果を取得 ・結果に応じて 登録中画面 正常終了画面 エラー画面 を表示 登録中画面 ・METAタグを使って○秒おきにチェックするサーブレットに 要求を投げる こんな感じでいかがでしょうか。 サーブレットの処理にキャンセルをかけるのは… サーブレットも要求ごとに別スレッドになってるので…割り込み?掛ければできるのかもしれないけど、やったことありません… Treadクラスにinterrupt()メソッドがありますね…。
お礼
ご回答ありがとうございす。 詳細に解説いただき、大変勉強になります。 >「閉じたり」はわかりますが、サーブレット1本でやった場合に、他のリンクをクリックできます? 処理メニューなど、フレーム分割されている場合を 想定しておりました。 >「動いてますよ!止まってませんよ!!」 >ってことをアピールすれば「×」ボタンは押されにくくなるかもしれません。 そうなんですよね。これは大事だと思います。 貴重な時間を割いていただき、ありがとうございました。