モバイルとは全く関係ないですが、自分のメモ代わりに記事にしてみたいと思います。
たまたまテストしていて、MySQLとPostgreSQLのRepeatable Read時の挙動の違いを見つけました。
AさんとBさんという二人のユーザが同時に一つのレコードを更新している場合です。
user_tblのuser_typeというカラムを「0」→「1」にアップデートしています。
分離レベルはMySQL、PostgreSQLともにRepeatable Readです。
|
Aさん
|
Bさん
|
||
| mysql> begin; Query OK, 0 rows affected (0.00 sec) |
トランザクション開始 | ||
| mysql> select user_type from user_tbl where user_id = 1000; +———–+ | user_type | +———–+ | 0 | +———–+ 1 row in set (0.00 sec) |
参照 | ||
| mysql> begin; Query OK, 0 rows affected (0.00 sec) |
トランザクション開始 | ||
| mysql> select user_type from user_tbl where user_id = 1000 for update; +———–+ | user_type | +———–+ | 0 | +———–+ 1 row in set (0.00 sec) |
行ロック | ||
| mysql> update user_tbl set user_type = 1 where user_id = 1000; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 |
更新 | ||
| mysql> commit; Query OK, 0 rows affected (0.05 sec) |
コミット | ||
| mysql> select user_type from user_tbl where user_id = 1000; +———–+ | user_type | +———–+ | 0 | +———–+ 1 row in set (0.00 sec) |
参照(ロックなし) | ||
| mysql> select user_type from user_tbl where user_id = 1000 for update; +———–+ | user_type | +———–+ | 1 | +———–+ 1 row in set (0.00 sec) |
参照(ロックあり)
※結果が違うことに注意 |
||
最後のSELECTが、「FOR UPDATE」の有り無しで違う結果を返していることにご注意ください。
FOR UPDATE以外は全く同じSQL文なのに、結果が違うというのは、少し違和感がありますね。
|
Aさん
|
Bさん
|
||
| test=# begin; BEGIN |
トランザクション開始 | ||
| test=# select user_type from user_tbl where user_id = 1000; user_type ———– 1 (1 row) |
参照 | ||
| test=# begin; BEGIN |
トランザクション開始 | ||
| test=# select user_type from user_tbl where user_id = 1000 for update; user_type ———– 1 (1 row) |
行ロック | ||
| test=# update user_tbl set user_type = 0 where user_id = 1000; UPDATE 1 |
更新 | ||
| test=# commit; COMMIT |
コミット | ||
| test=# select user_type from user_tbl where user_id = 1000; user_type ———– 0 (1 row) |
参照(ロックなし) | ||
| test=# select user_type from user_tbl where user_id = 1000 for update; user_type ———– 0 (1 row) |
参照(ロックあり) | ||
PostgreSQLの場合は「FOR UPDATE」の有る無しでSELECTの結果は変わりません。
こちらの方が直感的な感じがしますね。
(MySQLの内部構造には詳しくないのできっとですが)MySQLでは最初のSELECTでスナップショットが展開されるので、FOR UPDATEで取得した場合とそうじゃない場合でSELECTの結果が違うのだと思います。
「あるテーブルの値を元に、他テーブルの値を更新する」みたいなプログラムの場合、上記の例のようなパターンにはまることがありそうです。
そのような参照の前にはしっかりロックをかけましょう、というそんなお話でした。
関連:

携帯サイト年鑑2010
ブックレビュー:ユーザー視点でつくる 携帯サイト制作の基礎知識
ブックレビュー:mixiアプリをつくろう!OpenSocialで学ぶソーシャルアプリ
Ruby on Rails携帯サイト開発技法
携帯サイト制作 WEBデザインの新しいルール
PHP×携帯サイト デベロッパーズバイブル
ケータイHTMLコンパクトリファレンス
札幌のケータイ開発、Web開発なら

