こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

同一ユーザーが同時アクセスした時のトランザクション

PHPとMySQLでWEBアプリを作っています。
複数の人がログインしてデータの書き換えが発生するので、トランザクションを扱いたいと考えています。
サイトや書籍を見て基礎はとりあえず頭に入ったのですが、自分の作っているアプリで一般的にどうやればいいのかピンときていません。
そこでいくつか疑問があるのですが、今回的を一つに絞って質問します。

質問
「同じアカウントのユーザーが別々のブラウザから同時にアクセスしてきても問題が無いようにする一般的なトランザクション処理の方法が知りたい」

現在既に出来ているアプリの流れが以下です。(かなり簡略化しています)

<?php
 始めにMySQLでユーザー情報の読み込み

 MySQLでいろんな情報の読み込み
 phpでいろんな処理
 MySQLでいろんな情報の書き込み
 (上記の一連の処理は何回も出てくる)

 最後にMySQLでユーザー情報の書き込み
?>


書籍やサイトに載っているトランザクションの例だと、読み込みと書き込みの一連の流れが連続しているので単純にSTART TRANSACTIONしてCOMMITしている場合が多いです。
しかしこのアプリの場合ユーザー情報の読み込みと書き込みに間が空いているので、この間をSTART TRANSACTIONとCOMMITで挟む、というのはかなりおかしい気もします。

このような場合に同一アカウントからの同時アクセスでも整合性を保つにはどうやるのが一般的なのでしょうか。
根本的にphpプログラムとしてデザインが間違っているのかもしれませんが、あくまでMySQLのトランザクション処理での解決を目指している(もうプログラムはほぼ完成している)ので、MySQLのカテゴリで質問しました。でもそういう指摘もしてもらえるとありがたいです。

(ちなみにこのようなことはあくまでそういうアクセスをしてくる人のまれな状況のための対処であり、頻度としては高くないと思っていますがまずは最初の疑問としてあげました)

投稿日時 - 2012-10-17 01:29:58

QNo.7752234

すぐに回答ほしいです

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

No1です。

そのPHPファイル1つの中でトランザクションを完結させるという前提ということでしょうか?

でしたら、MySQLのDBをInnoDBで作成し、以下のような手順で行えば排他処理を実現できます。

1.start transactionを宣言
2.更新対象テーブルに対して、select ~ for update(もしくは、select ~ lock in share mode)でレコードロックをかける
3.そのレコードに対して何かしらのupdate等のメイン処理
4.commitし、トランザクション終了

InnoDB以外のトランザクションをサポートしてないエンジンを使用する場合、もしくは、複数のPHPファイル(複数のHTML)にまたがって処理を行いたい場合は、以下のような手順となります。

1.最初に更新対象となるレコードの値ををphpのセッションに保存
2.何らかの処理を実施
3.更新処理直前に、最初に保存した値をphpのセッションから取得、更新対象のデータを再度参照し、値が違っていたら更新処理を中断、同じであったら更新処理を実施

等のロジックがどうしても必要になります。

※ちなみにですが、phpのセッションは、ブラウザや、ブラウザのタブ毎に必ず一意となるようになっているので、仮に1つのPCで複数のブラウザやタブを開いても、それらは、別なセッションとみなされます。

これで回答になってますでしょうか。

投稿日時 - 2012-10-18 10:28:26

お礼

InnoDBを使っていまして、まさにずばりです。
ありがとうございました!

投稿日時 - 2012-10-18 21:45:47

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(2)

PHPには、sessionという概念がありますので、それを利用するのが一般的です。

以下に参考URLを貼ります。

url : http://c-brains.jp/blog/wsg/08/05/22-193020.php

投稿日時 - 2012-10-17 11:18:01

補足

回答ありがとうございます。
セッションは既に取り入れているのですが、今回の問題にセッションを使ってどう対処するのでしょうか。

説明不足だったので今回の問題をもうちょっと詳しく記載します。
例えばユーザーがアクセス(アクセスA)してきてphpやmysqlの処理が行われている真っ最中に同じユーザーが別のブラウザでアクセス(アクセスB)してくるというごく短い時間でのことです。

1:アクセスAでユーザー情報を読み込んだ後、アクセスBがユーザー情報読み込む
2:アクセスAが変更されたユーザー情報を書き込んだ後、アクセスBが変更されたユーザー情報を書き込む

なんかこう書いていて結局アクセスBの結果でいいのではないかという感じもしますが、問題が出てきそうなのでこういう問題の一般的な回避方法が知りたいのです。
つまり同一ユーザーの同時アクセスの排他処理がしたいということです。

真っ先に思いついたのはアクセスしたらすぐユーザー情報に現在処理中であるというフラグをデータベースに書き込んで、全処理が終わったらフラグを下げるという方法です。
でもこんなまわりくどい方法をみんなやっているのだろうかと疑問であります。

そこでトランザクションかロックで問題解決できるんではなかろうかと思っている次第です。

投稿日時 - 2012-10-17 13:17:13

あなたにオススメの質問