datchの日記

気がついたら社会人。気になる技術的なことについて少しずつ書いていけたらと思っております。

【Sunrise2nd 復習】トランザクション

どうも、スノボで満身創痍になってちょっと体調を崩してました。

今日も前回の続きでSunrise2ndのMySQLの講義で習った事を復習して行きたいと思います。

【Sunrise2nd 復習】レプリケーション - datchの日記

ここらへんは何気なく知っていたトランザクションをより深く知ることが出来ました。

分離レベルなど、日頃聞かなかったようなことを知ることが出来たので非常に有意義な事を学べました。


「Sunrise2nd」で使用しているMySQLの参考書

参考書は上記の本を使用している。

あまり内容を書きすぎると色々と問題にもなるので、もっと内容を深く知りたい方は上の広告をわざわざクリックして飛ばなくてもいいので、買って読んでみることをオススメします。

現在まで4回の講義が行われているが、今回は3回目に行われた「トランザクション」について触れたいと思う。

トランザクション

トランザクションの概要

そもそもトランザクションって何?

今回も偉大なwikipedia先生やIT用語辞典を見てみよう。

トランザクション - Wikipedia

トランザクションとは 【 transaction 】 - 意味/解説/説明/定義 : IT用語辞典

トランザクションとは一連のSQL文をAtomic(全てのクエリが実行・反映される、されない)処理される仕組み、と考えていい。

ACID特性とは?

補足ではあるが、ここでACID特性について説明したいと思う。

ACID特性とは原子性(atomicity),一貫性((consistency),独立性(isolation),および永続性(durability)の接頭辞を取ったもの。

これに関してはWipedia先生が分かりやすい文章で説明してくれている。

ACID (コンピュータ科学) - Wikipedia

トランザクションの基礎知識

トランザクションの用語
  1. コミット
    コミットされるまで、そのトランザクションMySQLへの変更を確定させる処理。
  2. ロールバック
    コミット前にトランザクション中に行われた処理を全て取り消す処理。
  3. MyISAM
    テーブルを作成した時に標準で採用されるデータベースエンジン。トランザクションが使用できない。
    また後述する自動コミット機能と同じく単一のSQL文を実行する毎にコミットされ、ロールバックができない。
  4. InnoDB
    安定性、実績からよく使われるデータベースエンジン。トランザクションが使用できる。
MySQLでのトランザクションの開始と終了

START TRANSACTION句(MySQLの場合はBEGIN, BEGIN WORK句も対応しているが、互換性の観点からここでは使わない)とトランザクションを開始し、

COMMIT, ROLLBACK文によってトランザクションを能動的に終了させる。

後で説明するが、終了する条件は他にもあるが、それはエラーによる終了になる。

自動コミット

MySQLには自動コミットと呼ばれる機能があり、この機能を有効にするかどうかで、トランザクションの開始/終了の方法が変化する。

自動コミットの特徴は次の通り。

  1. 有効にした場合(デフォルト)
    トランザクションは単一のSQL文を実行した時点で自動的、もしくはSTART TRANSACTION文によって明示的に開始する。
    単一のSQL文はクエリの終了と同時にコミットされ、ロールバックはできない。
    START TRANSACTION文を実行している場合は、COMMIT文を実行した時点ではじめてコミットする。
  2. 無効にした場合
    トランザクションは、SQL文の実行によって暗黙的に、またはSTART TRANSACTION文で明示的に開始する。いずれのの場合も自動的にコミットはしない。COMMIT文を実行した時点でコミットし、ROLLBACK文を実行した時点でロールバックする。

色々と面倒な事が書いてあるが、要するにトランザクション中でない単一のSQL文(START TRANSACTION文とCOMMIT文の間にない)が自動でコミットされるか、されないかだけの違いである。

ちなみに、OracleのDBでは自動コミットがデフォルトで無効になっており、移行時にエンジニアがはまりやすいポイントらしい。

以下のクエリをMySQLで叩くことで自動コミットを有効無効に出来る。

SET AUTOCOMMIT=0; # 0なら無効、1なら有効
SELECT @@autocommit; # 自動コミットのパラメータを取得できる
ロールバック

InnoDBではトランザクション単位でのロールバックだけでなく、SQL文単位でのロールバックが出来る。

これはSQL文の構成違反や制約違反などが発生した場合は、そのSQL文だけが無効になり、トランザクションは継続する。

2相コミット

本章では2相コミットについても言及していたが、ここでは省く。

・ロック

ロックの種類

ロックとは他のトランザクションのアクセスを制御する排他制御の仕組みである。

ロックの範囲は行単位でロックが行われ、

これには二種類のロックが用意されており、

  • 排他ロック
    INSERT、UPDATE、DELETE文のような更新処理にこのロックが適用される。
    この状態では他のトランザクションからはロックが解除されるまで何も出来ずロックの解除待ち(ロック待ち状態)になる。
  • 共有ロック
    共有ロックは重複して行うことが出来、排他ロックを掛けられないようさせるロック。

標準のMyISAMではSELECT文を実行すると自動的に共有ロックが掛けられる。

ロック処理を行うSQL

ロック処理を行うSQL文を記載する。

  1. SELECT ... FOR UPDATE:排他ロック
  2. SELECT ... LOCK IN SHARE MODE:排他ロック、または共有ロック
  3. FLUSH TABLES WITH READ LOCK:共有ロック
  4. LOCK TABLES / UNLOCK TABLES:共有ロック
分離レベル

ここらへんからあまり耳にしたことのない内容で個人的に高度な内容だと感じている。

分離レベルとはそれぞれ同じSQL文でもコミットしていないデータに対する処理や、実行順番を変化させる仕組みのこと。

グローバルレベルだけでなく、セッション毎にも分離レベルを個別に設定することが出来る。

以下の構文でセッション毎に分離レベルをそれぞれ設定することが出来る。

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL { Read Uncommitted | Read Committed | Repeatable Read | Serializable }; # 設定
SELECT @@tx_isolation; # 取得

グローバルレベルで設定したい場合には以下の構文を用いる。

transaction-isolation = {Read-Uncommitted | Read-Committed | Repeatable-Read | Serializable}; # 設定
SELECT @@global.tx_isolation; # 取得

それぞれ分離レベルを説明すると以下のようになる。

  1. Read Uncommitted : 他のトランザクションでコミットしていないデータをSELECT文に反映して取得する。
  2. Read Committed : コミットしていないデータはSELECT文で取得してもに反映されない。
  3. Repeatable Read : SELECT文中にテーブルに変更が加えられても、SELECT文開始時のデータが読み込まれることが保証される読み方。
  4. Serializable : これの理解はあまり追い付いていないのが、最も安全に読み込みが行われる。

なお、説明下手な私の文章よりもWikipediaさんに聞いた方が分かりやすいと思うのでリンクを載せておく。

トランザクション分離レベル - Wikipedia

分離レベルによるケーススタディ

この章では分離レベルによって動作が異なる事例を紹介しているが、この事例を全て載せると著作権的にも文量的にも新しい記事が掛けてしまうので触りだけにする。

動作の違いによって以下の問題が発生するので、各自でその動作についての詳細は調べて欲しい。

  1. ロストアップデート
  2. ダーティリード
  3. 反復読み込み不能
  4. ファントムリード
  5. デッドロック
  6. インデックス未定義によるテーブル・ロック
  7. ネクストキーロッキング

おわりに

最後まで読んで頂きありがとうございました。

最後の方は投げっぱなしになってしまいましたが、やはり分離レベルまでの踏み込んだ話になると全然知らない事ばかりでした。

今回の勉強会で一番勉強になったのは分離レベルについてだったので個人的にはとてもためになったと思います。