@IT会議室は、ITエンジニアに特化した質問・回答コミュニティ「QA@IT」に生まれ変わりました。ぜひご利用ください。
- PR -

MySQL4.0での排他制御(行ロック)の方法について

1
投稿者投稿内容
らすかる
会議室デビュー日: 2005/12/22
投稿数: 18
投稿日時: 2006-03-31 17:18
お世話になります。

OS:WindowsXP
言語:VS2005 ASP.NET(Web Application)
DB:MySQL4.0 (「MySQLDriverCS」での接続)

現在、MySQL4.0を利用して排他制御(行ロック)のプログラムを作成中なのですが
エラーが発生してしまい解決できない状態です。
以下に詳細を記載します。「解決策」「参考URL」等何でも構いませんので情報をお
願い致します。

<画面(説明)>
 ・1つ画面(aspx)を作成し、Page_Loadイベントに処理追加。
 ・1秒毎に処理されるように、リフレッシュを設定。

<プログラム(説明)>
 ・あるテーブルの項目(コード)を取得し、その時取得したコードを+1した値を
  Sessionに保持しておく。
 ・そのコードをUPDATE(更新)する。

<テーブル(InnoDB型)>
 インデックス番号  コード
−−−−−−−−−−−−−−−−−−
 1         001

<プログラム>
 ※エラー処理は、省略(Try 〜 Catch 〜 End Try使用)

'「MySQL」オープン後に、「START TRANSACTION」を実行
ret = MySQL_Connect("START TRANSACTION")

'トランザクションレベルの変更
cmd = New MySQLCommand("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE", con)
red = cmd.ExecuteReader()

'「LOCK IN SHARE MODE」でSELECT実行
cmd = New MySQLCommand("条件文(SELECT) LOCK IN SHARE MODE", con)
red = cmd.ExecuteReader()
While red.Read()
Session("K_NO") = 取得したコード+1した値
End While

'コードの更新処理
wSQL = Session("K_NO") を更新する(UPDATE)
cmd = New MySQLCommand(wSQL, con)
red = cmd.ExecuteReader()

'「COMMIT」実行
cmd = New MySQLCommand("COMMIT", con)
red = cmd.ExecuteReader()

'「MySQL」クローズ
Call MySQL_DisConnect()


<テスト方法>
 ・作成したプログラムを、サーバに設定する。
 ・2台のマシンから、このプログラムを呼び出す。

 ※PC1台では、エラーは発生しません。

<結果>
 ・2台同時に、別々のエラーが発生した時に画面が動作しなくなった。
  コードは「600」ぐらいまで正常に更新することが出来ていた。

 ●エラーメッセージ
  1、保護されているメモリに読み取りまたは書き込み操作を行おうとしました。
    他のメモリが壊れていることが考えられます。
    →「COMMIT」実行の時に発生!!

  2、MySQLDriverCS Error: can't connect・・・・
    →「MySQL」オープンで発生!!

エラー内容は分かるのですが、どうして起きるのかが全く分かりません。
かなり長い説明となり、申し訳ありません。よろしくお願いします。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-04-02 21:28
 コマンドを発行してトランザクションを実行するしかできませんか?OleDB や SQL Server 用の DbCommand クラスには、トランザクションクラスを受け取るコンストラクタがあるのですが。

 または、ストアドプロシージャ化してしまうか。コードからちまちまやるより、一回の呼び出しでできることはすませた方がいいと思います。

 あるいは、MySQL にはシーケンス(順序)オブジェクトはないのかな?それを使えば、いちいちロックする必要もないですよね(飛び番の発生を抑えたいという案件のようには見えない)。
coasm
大ベテラン
会議室デビュー日: 2001/11/26
投稿数: 237
投稿日時: 2006-04-02 21:59
share mode で lockしたレコードをupdateしてはいけません。
変更することを前提にlockするなら、select 〜 for update でlockしましょう。

共有ロックというのは、一連のレコードを読み出し中に
他のトランザクションから変更されたり削除されたりすることを防止するために、
読み出し側がロックするためのものです。
らすかる
会議室デビュー日: 2005/12/22
投稿数: 18
投稿日時: 2006-04-03 09:20
Jittaさん、coasmさん、返答ありがとうございます。
回答を参考に、再度作成していきます。
状況が変わり次第、再度回答致しますのでよろしくお願いします。


-----[Jittaさんの返答]-----
>コマンドを発行してトランザクションを実行するしかできませんか?
>OleDB や SQL Server 用の DbCommand クラスには、トランザクションクラスを
>受け取るコンストラクタがあるのですが。

「MySQL」の接続方法に関して調査していくと、「MySQLDriverCS」の接続方法の
サンプルがありました。それ以外は、いいサンプルが見つからない(調査不足?)
ので、現在の方法をとっています。
<参考>
http://www.vbstation.net/tips/mysql_conn.htm

>または、ストアドプロシージャ化してしまうか。コードからちまちまやるより、
>一回の呼び出しでできることはすませた方がいいと思います。

「ストアドプロシージャ化」とは、どういうやり方でしょうか?
参考となる情報がありましたら、教えて頂けないでしょうか?

>あるいは、MySQL にはシーケンス(順序)オブジェクトはないのかな?

これは、調査します。「MySQL」に関しては、調査不足の部分が多々あるので
勉強します。

-----[coasmさんの返答]-----
>share mode で lockしたレコードをupdateしてはいけません。
>変更することを前提にlockするなら、select 〜 for update でlockしましょう。

これは、知りませんでした。「select 〜 for update」で試してみます。

以上
らすかる
会議室デビュー日: 2005/12/22
投稿数: 18
投稿日時: 2006-04-06 15:24
お世話になります。

Jittaさん、coasmさんの回答を参考に修正を行い、解決することが出来ました。
本当にありがとうございました。

<修正内容>
1、各処理を分けてエラーチェックを行っていたが、全ての処理をひとまとめに
  してエラーチェックを行うように修正。
2、「SELECT 〜 LOCK IN SHARE MODE」を「SELECT 〜 FOR UPDATE」に修正。

<補足>
 Jittaさんの回答にある「ストアドプロシージャ化」について調査していたら、
対応する場合「MySQL5.0」でないと出来ないことが分かりました。
 その為、PCに「MySQL5.0.19」をインストールしてみました。しかし、「スト
アドプロシージャ化」する前に動作に問題がない事が確認出来たので、保留にして
います。

以上
1

スキルアップ/キャリアアップ(JOB@IT)