2人のユーザーが同時アクセス時のトランザクションで発生する問題と解決方法

このQ&Aのポイント
  • 2人のユーザーが同時アクセスした際に、mysqlデータベースにおいてAtomicity(原子性)が保たれない現象が発生することがあります。
  • 問題の現象は、同じレコードに対して行われるトランザクションの途中で中途半端な値を読み込んでしまうことです。
  • この問題は排他ロックをかけることやトランザクションのタイムアウトを設定することで解決することができます。
回答を見る
  • ベストアンサー

2人のユーザーが同時アクセス時のトランザクション

AユーザーとBユーザーがいてmysqlデータベース(innoDB)に同時アクセスします。 (実際にはphpから行っています) このときAtomicity(原子性)が保たれていないように見える現象が3割程度の確率で発生します。 以下がその問題の現象が発生する流れです。 error_logで出力したものです。 beginTransactionとcommitTransactionは、実際にはphpのpdoのメソッドを呼んでいます。 テーブル1 : state (初期値 0) テーブル2 : answer (初期値 0) stateに対しては常に行の排他ロックをかけている(必ずテーブル2に対するアクセス前) (念のため、stateに対するアクセスはもちろん同じレコードに対してです。 answerに対するアクセスももちろん同じレコードに対してです。) B : beginTransaction 前 B : beginTransaction 後 B : answer=0を読み込み確認 B : state=0を読み込み確認 B : answer=1を書き込む B : state=3を書き込む A : beginTransaction 前 A : beginTransaction 後 B : commitTransaction 前 :state=3を読み込み確認 B : commitTransaction 前 :answer=1を読み込み確認 A : state=3を読み込み確認 // 問題 A : answer=0を読み込み確認 // A : commitTransaction 前 :state=3を読み込み確認 A : commitTransaction 前 :answer=0を読み込み確認 B : commitTransaction 後 :state=3を読み込み確認 B : commitTransaction 後 :answer=1を読み込み確認 A : commitTransaction 後 :state=3を読み込み確認 A : commitTransaction 後 :answer=1を読み込み確認 問題はAユーザー側の途中の処理でstate=3とanswer=0という、中途半端な組み合わせの値を読み込んでしまっていることです。 あるべき状態はAユーザー側で、state=0とanswer=0あるいはstate=3とanswer=1と確認できることです。 一体何が起こっているのでしょうか。 また解決方法はどのようなものでしょうか。 直接の答えでなくてもヒントだけでも頂けると助かります。

  • MySQL
  • 回答数1
  • ありがとう数1

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

  • ベストアンサー
  • bugmaker
  • ベストアンサー率63% (12/19)
回答No.1

なんとなくですがBのコミット完了前にAが読みに行ってませんか? stateにはロックをかけるのに対しanswerにはかけていませんがその辺も確認したほうが良いかと思います。 Mysqlのリファレンスです。 ロック関連の問題 http://dev.mysql.com/doc/refman/5.1/ja/locking-issues.html これは検索でヒットしたブログですが参考になるかもしれません http://ikm.hatenablog.jp/entry/2012/12/10/192346

ankodaisuki
質問者

お礼

stateがFOR UPDATEにより最新のものを読み込んでいるのに対し、answerはスナップショットを読んでいてその違いが原因でした。 ありがとうございました。

ankodaisuki
質問者

補足

stateはSELECT FOR UPDATEにより行ロックをかけているので「A : state=3を読み込み確認 // 問題」に来た時点でBのCOMMITは既に完了したものと推測しています。もし完了していなければ待たされているはずです。 answerは確かにロックしていませんが、この場合順番がstateのほうが先なので問題ないと思っています。 という考えなのですがいかがでしょうか。 (リンクはとても参考になりました) ただちょっと思ったのはBのCOMMITがmysqlの内部的に行われているときstateのロックは外れたけど、まだCOMMIT作業は終わってなくてanswerを読んでしまっている、つまり全然アトミックでない、というまずあり得なさそうな想像もしています。 あとはトランザクションの開始がAとBでかぶっているのでその辺に問題があるのかなどです。

関連するQ&A

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

    PHPとMySQLでWEBアプリを作っています。 複数の人がログインしてデータの書き換えが発生するので、トランザクションを扱いたいと考えています。 サイトや書籍を見て基礎はとりあえず頭に入ったのですが、自分の作っているアプリで一般的にどうやればいいのかピンときていません。 そこでいくつか疑問があるのですが、今回的を一つに絞って質問します。 質問 「同じアカウントのユーザーが別々のブラウザから同時にアクセスしてきても問題が無いようにする一般的なトランザクション処理の方法が知りたい」 現在既に出来ているアプリの流れが以下です。(かなり簡略化しています) <?php  始めにMySQLでユーザー情報の読み込み  MySQLでいろんな情報の読み込み  phpでいろんな処理  MySQLでいろんな情報の書き込み  (上記の一連の処理は何回も出てくる)  最後にMySQLでユーザー情報の書き込み ?> 書籍やサイトに載っているトランザクションの例だと、読み込みと書き込みの一連の流れが連続しているので単純にSTART TRANSACTIONしてCOMMITしている場合が多いです。 しかしこのアプリの場合ユーザー情報の読み込みと書き込みに間が空いているので、この間をSTART TRANSACTIONとCOMMITで挟む、というのはかなりおかしい気もします。 このような場合に同一アカウントからの同時アクセスでも整合性を保つにはどうやるのが一般的なのでしょうか。 根本的にphpプログラムとしてデザインが間違っているのかもしれませんが、あくまでMySQLのトランザクション処理での解決を目指している(もうプログラムはほぼ完成している)ので、MySQLのカテゴリで質問しました。でもそういう指摘もしてもらえるとありがたいです。 (ちなみにこのようなことはあくまでそういうアクセスをしてくる人のまれな状況のための対処であり、頻度としては高くないと思っていますがまずは最初の疑問としてあげました)

    • ベストアンサー
    • MySQL
  • C#でトランザクション開始後参照出来ない

    言語:C# DB:SQLServer2008 1.トランザクション開始 2.テーブルAをUPDATE 3.色々な処理(省略) 4.テーブルAのUPDATE前の情報を参照 5.参照したテーブルをもとにテーブルBをUPDATE 6.すべての処理が正常だったら全テーブルコミット、1つでも失敗したら全テーブルロールバック 問題となっているのは 4.テーブルAのUPDATE前の情報を参照する際に、テーブルAがロックされていて参照出来ないことです。 トランザクション開始時に分離レベルを設定してみましたが同じ結果でした。 tran = con.BeginTransaction(分離レベル); お分かりになる方ご教授お願いします。

  • Access2003で

    Access2003で AテーブルとBテーブルがあります。 両テーブルにも、NOフィールドがあります。 両テーブルとも1からの数字を付与しています。 NOフィールドの他に名称などのフィールドがあります。 ここでお聞きしたいのですが、BテーブルのNOフィールドの2のレコードを、 AテーブルのNOフィールドの2のレコードに上書きしたいのですが、どうすれば良いでしょうか? ちなみにBテーブルには上書きしたいレコード(この例でいきますとフィールド2)だけが格納されています。 どうすれば良いでしょうか? よろしくお願いします。

  • 複数ユーザによる Access の同時使用について

    複数ユーザでAccessファイルを使用する場合の影響について教えてください。 <環境> データベースとなるAccessファイル(複数)は、共有のデータサーバ内にあります。 各ユーザは、各自が使用しているPCのAccessを起動して対象のAccessファイルを開き、編集・閲覧します。 全PCのOSはXP(SP3)、Accseeのバージョンは 2000 又は 2002 です。 誰かが開いている場合、レコードロック情報がエクスプローラに表示されるので、他の人にも使用中であることが分かるのですが、WordやExcelのように使用中である注記が表示されないので、これを確認しない人が使用する際に同時使用になってしまう可能性があります。 <質問> 1.あるユーザがファイルを使用中の時、他のユーザが編集を目的としてその使用中のファイルを開いた場合、後から開いたユーザは編集が可能でしょうか? 2.同時に開いている2ユーザがそれぞれ編集作業を行った場合、それぞれの内容は保存されますか? 3.同時に開いている2ユーザのうち、先に閉じたユーザが編集作業を行い、後に閉じたユーザが閲覧のみであった場合、先のユーザの編集内容は反映されますか? 基本的なことだと思うのですが、Access初心者であるため、理解できていません。 よろしくお願いします。

  • Access 結合プロパティについて

    Access2010ですが、クエリの結合プロパティについて教えて下さい。 【テーブルA】 1 A1 2 A2 3 A3 【テーブルB】 2 B2 3 B3 4 B4 と言うテーブルから 【結合クエリ】 1 A1 2 A2 B2 3 A3 B3 4 B4 を作りたいです。 ところが、結合プロパティでは、 ・テーブルAのレコードを全部 ・テーブルBのレコードを全部 と言うのは選べるのですが、 両方のテーブルいずれかにあればデータを持ってくる と言う設定が分かりません。 すみません。どなたか教えて下さい。 よろしくお願いいたします。

  • ACCESS アクセスで他のデータベースからのデータインポート

    アクセスど初心者です。 Aというデータベースファイルにあるテーブルaのデータを、Bというデータベスファイルにあるテーブルbに インポートできますか?フィールド等詳細は両テーブルとも一緒だとします。 イメージ的には、テーブルbの最終レコードの後にテーブルaのデータがくっつくという感じです。 コピー&ペーストだとエラーになってしまうのですが・・・。宜しくお願いします。

  • アクセスのレポートについて

    アクセスでテーブルAのデータをレコードソースとするレポートAを作成したのですが、レポートAのなかにテーブルBのレコードソースを追加することは可能でしょうか。  また一からレポートを作り直さずにすむ方法が知りたいのですが。

  • Access2000で困ってます

    お世話になります Access2000で困っています あるデータベース(A)でVBAをさわっていたら おかしくなってしまいました そこで一週間ほど前にBackupのつもりで ファイル名を変えて保存した同じデータベース(B)を 使おうと思うのですがこの一週間であるテーブルのデータを 変更しています どのレコードのどのフィールドを変更したのかわかりません そこでデータベース(A)のテーブルとデータベース(B)のテーブルを 比較照合したいのですがどうすればうまくできるでしょうか? アドバイスお願いします

  • Accessで2つのテーブルのデータの整合性を確認したい

    Accessで2つのテーブルのデータの整合性を確認したいのですが、よい方法を教えていただけませんか? 状況は以下のとおりです。 Aテーブル    a   b    c   d   e       1  111  222  333  444  555 2  666   777 888 999 100 3   110 112 113 114 115 Bテーブル    a   b    c   d   e       1  111 222 333 444 555 2  666 777 000 999 100 3   110 112 300 400 500 ・AテーブルとBテーブルがあり、それぞれのテーブルのa、b、dフィールドのみを対象に、その値がAテーブルとBテーブルとで等しいかどうか調べたい。 (c、eフィールドの値が異なっていても、a、b、dフィールドの値が同じであればそのレコードはOKとし、a、b、dフィールドで1つでも異なる値があればNGとし、抽出したい。 例えば、Bテーブルの1、2レコードはOKだが、3レコードはNG) ・それぞれのテーブルのaフィールドが主キーになっている。 うまく説明できず、わかりにくいかもしれませんが、よろしくお願いします。

  • トランザクション中に別のトランザクションは開始できますか?

    DBはサイベースを使っています。初心者です。 以下のような動作をしているシステムの一部を改造することになりました。 1)カーソルAオープン 2)トランザクション開始 3)フェッチ 4)1トランザクションでの処理数分終了済みでなければ、3)から繰り返し 5)commit/rollback 6)終了済みでなければ 2)から繰り返し 7)カーソルAクローズ 今回、3)でフェッチしたレコードのある項目をキーとして 別のテーブルを検索しなければならないのですが、 3)の後に、カーソルBオープンとフェッチのみを追加しただけでは問題があると思うのですが、同一プロセスから、トランザクション中に別のトランザクションを開始することは可能なのでしょうか? なお、このトランザクションでは、レコードの追加や削除は行いません。 どうぞよろしくお願いいたします。