• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:SELECT時の行ロックの必要性について)

SELECT時の行ロックの必要性とは?運用上の利用方法を解説

このQ&Aのポイント
  • SELECT時の行ロックの必要性とは何か、運用上の利用方法について解説します。
  • SELECT ~ FOR UPDATEやSELECT ~ LOCK IN SHARE MODEといった行ロックの使い方について解説します。
  • 運用上の利用方法やロックの振る舞いについて、詳しく解説していきます。

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

  • ベストアンサー
  • maiko0318
  • ベストアンサー率21% (1483/6969)
回答No.4

>>質問3.select だから意味があります。 ただの読み込みではなく、「更新のための読み込み」であるということを明示しています。 updateやinsertは更新と決まっています。 >BIGIN; UPDATE tb_a SET price = 残高-10000 WHERE id = xxx; INSERT tb_a (price) VALUE (10000) WHERE id = yyy; COMMIT; ですよね? 合ってます。 2行だけロックされて他からは読み込めません。 >これはつまり、SELECT~FOR UPDATEとは選択のためのクエリーではなく「行ロックします」というクエリーなのですか? そして上のBIGIN~UPDATE~INSERT~COMMITは以下のように書かないといけないのでしょうか? BIGIN; SELECT * FROM tb_a WHERE id = xxx FOR UPDATE; SELECT * FROM tb_a WHERE id = yyy FOR UPDATE; UPDATE tb_a SET price = 残高-10000 WHERE id = xxx; INSERT tb_a (price) VALUE (10000) WHERE id = yyy; COMMIT; 読みたいときにselect,更新したいときにupdate、追加したいときにinsertでいいです。 つまり、上2行のselect は不要なのですが、 UPDATE tb_a SET price = 残高-10000 WHERE id = xxx; ここ、残高は先に読んで10000円あるかどうか確認しないといけませんよね。 こういう場合は SELECT 残高 FROM tb_a WHERE id = xxx FOR UPDATE; UPDATE tb_a SET price = 残高-10000 WHERE id = xxx; となります。 他の情報で10000円があることが確認されていればselectは不要になります。

suffre
質問者

お礼

再度のご回答、ありがとうございます。 >ただの読み込みではなく、「更新のための読み込み」であるということを明示しています。 >他の情報で10000円があることが確認されていればselectは不要になります。 これが知りたかったのです。 「更新の前段階において確認のための読み込みが不要」であればSELECT~FOR UPDATEやLOCK IN…はいらないということですね。 SELECT~FOR UPDATEについて解説しているサイトは多かったですが、運用や実例について解説しているサイトがなかったので疑問に思っていました。

その他の回答 (3)

  • maiko0318
  • ベストアンサー率21% (1483/6969)
回答No.3

こんばんは。仕事で数多く大型コンピュータで仕事していました。 私が使っていた大型コンピュータで説明します。 質問1.まず、これは無意味です。for update でロックしたのに、何もせずに開放しています。 質問2.トランザクションを開始した時には何もロックされません。 質問3.select だから意味があります。 質問4.以下参照 基本的なことから。 データベースをロックするという考え方。つまり、データって1件で独立していないですよね。 必ず関連があるものです。 銀行へ行ってATMで1万円出金する場合、口座から1万円引くという処理と 1万円札を出すという処理がありますが、これは同時に完了しなければなりません。 口座から1万円引いたのに、お金が出てこなかったら困りますよね。 つまり、 ---トランザクション開始 口座から1万円引く 1万円札を出す --トランザクション終了 ということです。 トランザクションの処理が全て完了した時commitし、どこかにミスがあればrollbackで戻すのです。 口座から1万円引いたけど、1万円札が機械にない。となったらrollbackして 口座から1万円引いたものをもとに戻すのです。 よってもとに戻すデータを他から変更されていては戻せなくなってしまいますよね。 なので「このデータは変更中だから変更しないで」という意味でロックされるのです。 ちまたでは「仮押さえ」などといいますよね。全部押さえられたら本契約するような。 SELECT * FROM tb_a WHERE id = 1 FOR UPDATE; と書けば変更するからロックしますよ。ということですのですぐにcommitするのはありえないです。 単にSELECT * FROM tb_a WHERE id = 1; と書きます。 FOR UPDATEと書いた時点でロックが掛かります。 UPDATEやDELETEは単にBEGINE;とCOMMIT;で囲えばいいだけですよね? ここまで書けば自明ですよね。 BEGIN; select ... select ... update ... insert ... commit; ですので。 select のあとすぐにcommitする例、これはまれにfor updateを書かなくても ロックが掛かる処理系があるためです。 処理件数/テーブルの件数が大きい時(ということはテーブルの大部分のデータを読んでいるとき)、 テーブル全体をロックしたほうが早い時があります。 これに対応するとテーブル件数が少ない時にはcommitをはさまないと テーブルが読めなくなってしまうのです。

suffre
質問者

お礼

ありがとうございます。 >質問3.select だから意味があります。 すみません、なぜでしょうか…? 理由も書いていただけると助かります。 >---トランザクション開始 >口座から1万円引く >1万円札を出す >--トランザクション終了 はい、これはわかります。 BIGIN; UPDATE tb_a SET price = 残高-10000 WHERE id = xxx; INSERT tb_a (price) VALUE (10000) WHERE id = yyy; COMMIT; ですよね? このクエリーだけでidがxxxとyyyが行ロック(場合によってテーブルロック)するわけではないのですか? もし認識が間違っていたら教えてください。 >SELECT * FROM tb_a WHERE id = 1 FOR UPDATE; >と書けば変更するからロックしますよ これはつまり、SELECT~FOR UPDATEとは選択のためのクエリーではなく「行ロックします」というクエリーなのですか? そして上のBIGIN~UPDATE~INSERT~COMMITは以下のように書かないといけないのでしょうか? BIGIN; SELECT * FROM tb_a WHERE id = xxx FOR UPDATE; SELECT * FROM tb_a WHERE id = yyy FOR UPDATE; UPDATE tb_a SET price = 残高-10000 WHERE id = xxx; INSERT tb_a (price) VALUE (10000) WHERE id = yyy; COMMIT; 度々すみませんがどうぞよろしくお願い致します。

  • ok-kaneto
  • ベストアンサー率39% (1798/4531)
回答No.2

読み取り一貫性が保証されないから http://gyouza-daisuki.hatenablog.com/entry/2013/11/19/150838 同時実行されている他のトランザクションでレコードを操作された場合、トランザクションの最初と最後で同じクエリーを発行した場合に同じデータでないと都合が悪い事もあるので、SELECTだけでもロックを掛ける場合があります。

suffre
質問者

お礼

ありがとうございます。 逆に言うと都合が悪くなければSELECTでトランザクションはしなくていいという解釈でいいでしょうか?

  • bin-chan
  • ベストアンサー率33% (1403/4213)
回答No.1

口座残高を題材にすることが多いと思います。 atmarkITさんのWebページ SQL実践講座(25): トランザクションでデータの不整合を防ぐ「

参考URL:
http://www.atmarkit.co.jp/ait/articles/0210/24/news001.html
suffre
質問者

お礼

ありがとうございます。 教えていただいたリンク先ではSELECT時にトランザクションすることは書かれていないようでした…。あとデータベースもMicrosoftのですし…。

関連するQ&A