一般社団法人 全国個人事業主支援協会

COLUMN コラム

こんにちは。Webエンジニアの篠原です。

世の中、二重実行できてはならない操作があります。例えば、

  • 商品の購入ボタンを2回押してしまった
  • 別々の人がたまたま同時に記事を更新したら、片方の内容が消えてしまった。

など…。
あってはならないですが、Webシステムを構築しているといつかは突き当たる問題です。

二重実行と言っても、大きく分けると2つのケースがある認識です。

同じ操作を自分で2回やってしまう

手が滑って2回ボタンを押してしまったり、画面が更新されないからと2度3度とボタンを押してしまう。
意図したものか、そうでないかは関係なく、複数回同じ操作のリクエストがWebサーバーに送られてしまうと、未対策のシステムではその数だけ処理が実行されてしまいます。
どのように防げば良いか。

画面側

主にJavaScriptでの対策ですが、ボタンが押下されたらそのボタンを非活性にしたり、画面ロックをかけましょう。
また、処理中であることを示すインジケーター(ぐるぐるするマークとか)を表示したり、時間がかかる処理であればプログレスバーを表示したりするのも親切ですね。

サーバー側でのチェックではないため、根本的な対策ではありませんが、経験則上、抑止効果はかなりあります。
プラグインで比較的簡単にできる対策も多いので、ぜひ導入しましょう。

サーバー側

システムとしての整合性を保つためには、サーバー側のチェックも必ず行います。
リクエストごとに一度だけ有効なワンタイムトークンを発行し、使用済みであればRejectするなどの処理を追加します。
ワンタイムトークンの管理はサーバーセッションやRedisを使用することとなるでしょう(中にはDBで管理しているプロジェクトもありました)。

また、情報登録・更新やなんらかの状態変更後に画面遷移する場合(通常POSTリクエストなど)は、処理完了後にページのリダイレクトを行うようにしましょう。こうすることで、更新完了画面で画面を更新した場合も、二重でPOSTリクエストが発生するのを防ぐことができます。

同じ操作を複数人が2回やってしまう

仮に複数人がログインして使用するシステムがあって、まったく同じ操作を、複数人が同時に実行した場合は、上記の対策では防ぐことができません。

このようなケースを防ぐには、画面側ではなく、サーバー側で対策を行う必要があります。

サーバー側

お互いのリクエストが同時に実行されないよう排他制御をかけることとなります。
排他制御の仕組みとして、最も安全と考えられるのはDBのロック機構を使用することです。

トランザクションを利用した悲観的ロックは最も確実ですが、処理しているリクエスト以外を待たせてしまったり、デッドロックを引き起こしやすいなどの難点があります。よりデッドロックの可能性が少ない、ロックバージョンを用いた楽観的ロックが採用される場合もあります。

なお、DBを使用していない環境では、ファイルをロックオブジェクトとして使用するケースも多いです。

まとめ

プロジェクト上でどこまでの精度が必要となるかによりますが、大半のアプリではここまで挙げてきた内容が最低限必要です。

一見すると簡単なWebシステムであっても、工数や予算がかかる背景には、お客さまからは直接要求されていない、こうした対策をしなければならない事情もあります。

フレームワークやライブラリで解決できるものはうまく活用していきたいですね。

The following two tabs change content below.

篠原 透

2015年より企業SEとして勤務し、Javaを中心とした業務系Webアプリケーションの設計・開発・運用を経験。2019年2月に独立し、個人事業主となる。

最新記事 by 篠原 透 (全て見る)

この記事をシェアする

  • Twitterでシェア
  • Facebookでシェア
  • LINEでシェア