カイワレの大冒険 Third

技術的なことや他愛もないことをたまに書いてます

どうして「InnoDBのREPEATABLE READでハマった話」という記事を書いたのか

今日@kuwa_twさんとチャットで、あの記事ゴチャゴチャしてて、最後まで読むのツライと言われたので、要点を絞って書いてみます(@kuwa_twさんをdisってるわけではないですよ!!!)。

該当の記事はこちら。 blog.masudak.net

まず、MySQL5.5系のInnoDBのトランザクションについて復習をば。

分離レベルに関してはググって他の記事を見ていただくとして、ファジーリード、ファントムリード、ダーティーリード、ロストアップデートといったトランザクションに関わる問題のうち、MySQL5.5系のInnoDB(REPEATABLE READ)では一般的にロストアップデートしか生じないとされています。

まず他のトランザクションのコミットの影響によって値の変化が生じるファジーリードですが、ネクストキーロック機能により、INSERTもUPDATEもさせないようにするので、値は変更しない設計となっています。 また、INSERTができないので、当然ファントムリードも発生しないことになっています。

このあたりはsh2さんのMySQL InnoDBのネクストキーロック おさらい - SH2の日記で復習するのがよいでしょう。また、コミット以前にINSERTとかができないので、ダーティーリードも発生しないはずです。 ただし、トランザクション内でフェッチした値を保持していますので、その結果ロストアップデートが生じてしまうことになります。

このような認識をしていました。InnoDBでREPEATABLE READにしているなら、ロストアップデートしか生じないはずと。

しかしながら、「特定の条件」の場合に限って、ファジーリードやファントムリードも発生することが伺えました。 というのが、先日公開した記事です。

んで、特定の条件というのは、具体的な数値ではなく、「num = num + 1」のようにカラム名を指定して変数のように使った場合です。

このようにSQL文に書いた場合、このnumはトランザクション開始時の値ではなく、SQL発行時の値を参考にすることになり、「他のトランザクションでコミットされた内容」に影響を受けます。

そのため、ファジーリードやファントムリードが発生することになります。 上記のようなSQL文を使っていないとか、使っていても想定内ということであれば全く問題ないのですが、僕が知る限りこのような指摘見つけられなかった(ググる力が低いだけかもしれない)ので、備忘録の意味でも残しておきます。 不明な点・間違った点があれば、@masudaKまでお願いします!!