【ORACLE】FOR UPDATEの勘違いと真実(今さら)、あと実験
Oracleの「FOR UPDATE OF TABLE.COLUMN」は、指定した項目を基準としてレコードの排他をかける構文だと思ってたが、
SELECTの対象が複数存在する場合にどのテーブルをロックするかを指定するもとの情報らしくて、
SELECT対象が1テーブルだけだとあまり意味がないらしい。
また、仮に複数あったとしても、「そのテーブルを(ロックする)」という意味しか持たず、
項目を指定することによる、その項目に関連する排他の意味合いはないようだ。(じゃあ書かせんなよ…FOR UPDATE OF TABLEだけ(COLUMN書く必要ない)でいいやんけ)
要するに項目Aと項目Bがあったら「FOR UPDATE OF 項目A」でも「FOR UPDATE OF 項目B」でも効果は同じ、ということらしい。
なお、前提として、ここでいう「そのテーブルを」というのは、FOR UPDATEを付けているSELECT側の条件(WHERE句等)に左右される。
つまり「テーブル全体をロックする」という意味ではなくて指定された条件に該当するレコードのみがロックされる。
まあでも確かに冷静に考えると、
指定した項目によっては「(その項目を指定したからって)だから何?」っていう気になるのもわかる。
これは、自身のプロジェクトにおいて、「FOR UPDATE OF TABLE.COLUMN」の「COLUMN」に指定される項目が、
得てしてKEY項目であることが多いことに由来するのだろう。
つまり「そのKEYのレコード全体をロックする」という意味合いとして使っている(書いている)と、
結果的には勝手に”勘違いしていた”ことになるのだが、
そもそも、もともとFOR UPDATE OF TABLE.COLUMNの".COLUMN"には、
Oracle的には、項目自体に対する排他等の意味や目的はなくて、
「そのテーブルを」の判断基準にしか使ってないんだから、
指定されたからといって、例えばフラグ的意味合いの項目だったとすると”値が1のレコードだけロックするの?”とか、
様々疑問が出てくることは確かである。
それに、KEY以外の項目を指定したとしたら(あるいはKEYなしテーブルだったとしたら)、
排他ができない無意味な構文になるかというと、それはそれで本末転倒であるし、
そういうことも考えると「よく考えればわかるだろ」と言われるとそうでもある。
結合してデータを取得する際に同じ名前の項目が一度のSELECT内で複数存在する場合に、
「どのテーブルの」項目かを区別する指定を明記しないと実行できずに怒られる仕様がある。
このFOR UPDATEの項目指定もそれとよく似ていて、その理由というか、経緯も多分同じなんだろう。
「Aテーブル.項目B」と「Cテーブル.項目B」が存在するとき、
単に「FOR UPDATE OF 項目B」とだけ書いても「どっちのだよ?」という気になるから、テーブル名から書かせるようになっている…
そんなところなんだろう。
だから「テーブルどころか項目名まで書かせている」というよりは「項目を書かせるためにテーブルまで指定させている」というほうが正しい気がする。
でも項目を書くことの意味がない(指定する項目によって排他の効果は変わらない)なら出発点がまず間違っていると思うのだ。
(これは俺の予想に過ぎないから事実がどうかは知らない…)