データベースのロックについて

<h1>・はじめに</h1>
　この記事は、サポーターズ主催のCARTA HOLDINGS社による『DBのロックについてあまり意識したことがない人に向けた、実は覚えておきたいロックについての知識』に参加したので、それについてのアウトプットの記事です。

<h1>・ロックとは</h1>
　DBにおける<b>ロック</b>とは「データのアクセスから処理までの一連の流れが終わるまで、他のプログラムはそのリソースに<b>アクセスすることができない</b>ようにすること」をいいます。これは複数のプログラムが同じリソースにアクセスをした際に起こってしまう不具合を防ぐために行います。
<br><br>
<h2>・具体例</h2>


![スライド1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850098/ad01b4c1-182c-1e69-1223-fb721648964d.png)

<ol>
<li>Aさんが<b>口座の残高の情報を取り出す。</b>残高である1000を残高変数に代入する。</li>
<li>Bさんも<b>口座の残高の情報を取り出す。</b>残高である1000を残高変数に代入する。</li>
<li>Aさんが口座から1000円引き出す。残高変数から1000が引かれる。<b>残高変数は0円</b></li>
<li>Aさんの行った引き出しが残高に反映され、<b>残高は0円となる。</b></li>
<li>Bさんが口座に1000円入金する。残高変数から1000円が足される。Bさんは<b>13:05時点の残高の情報しか持っていない</b>のでもともとの残高変数である1000円に今回入金された1000円が追加され、<b>合計2000円になる。</b></li>
<li>Bさんの行った入金は<b>Aさんの行った引き出しに上書きされる形で反映される</b>ため、この口座の残高は<b>2000円</b>となってしまう。</li>
</ol>

<b>【ロックがかけられているときの説明】</b>
![スライド2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850098/b0700c16-9723-9517-edbb-e1114d176b85.png)
<ol>
<li>Aさんが<b>口座の残高の情報を取り出す。</b>残高である1000を残高変数に代入する。</li>
<li>Aさんがロックをかけたため、Bさんは<b>口座の残高の情報を取り出せない</b></li>
<li>Aさんが口座から1000円引き出す。残高変数から1000が引かれる。<b>残高変数は0円</b></li>
<li>Aさんの行った引き出しが残高に反映され、<b>残高は0円となる。</b>反映が終わったためロックが解除される。
<br>⇒Bさんはここではじめて口座にアクセスすることができる。</li>
</ol>

　このようにDBのロックは、一つの処理が終わるまでずっとそのリソースにアクセスできないようにすることによって複数のプログラムが同じリソースにアクセスした際に起こり得るバグを事前に防ぐことができます！

　しかし、ロックにもデメリットがありロックがかかることによって待機時間が増え、<b>プログラムの実行時間が長く</b>なってしまいます。さらにロックの設計にミスがある場合、ロック待ちが永遠と続いてしまう<b>デッドロック状態</b>になってしまう可能性もあります。

<h1>・共有ロックと排他ロックとは</h1>
　<b>共有ロック</b>とは、ロックと名のついている通りアクセスにロックをかけるものですが、他のプログラムも共有ロック処理を付けてプログラムを実行した時はロックに引っかからずに実行できる、<b>共有ロック同士は実行できる</b>というロックのことです。

![DBのロックについて.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850098/ce46eba0-fff3-1d75-36f4-a4422290ee60.png)

　対して<b>排他ロック</b>は、かけた場合<b>いかなるアクセスも許さない</b>ようにするロックのことです。このロックはどうしても値にバグが起きてしまうと困る場合、金銭の処理やポイントの処理などに使われます。

![DBのロックについて2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850098/f382bdd5-4418-6bbc-9524-c5136be86b83.png)
　MySQLの機能で<b>SELECT</b>する際は共有ロックがかけられ、<b>INSERT</b>、<b>UPDATE</b>、<b>DELETE</b>する際は排他ロックがかけられるようになっています。

<h1>・トランザクション分離レベルとは</h1>
　<b>トランザクション分離レベル</b>とは、ロックがどれほど他の処理に影響するか、それによって起こり得る不具合を表すものです。これはデータベースを設計する際に考えることになる<b>ACID特性</b>の<b>Isolation（＝分離性）</b>に関係する部分です。<br>
　このトランザクション分離レベルによって、引き起こしてしまう不具合の数が変わります。トランザクション分離レベルで起こる不具合の種類は3種類あり、<b>ダーティーリード</b>、<b>非リピータブルリード</b>、<b>ファントムリード</b>の3つです。

<h3>・ダーティーリードとは</h3>
　<b>ダーティーリード</b>とはロックがされていない(分離性が低い)時に発生する不具合で、別の処理でまだコミット（結果を反映）していない内容を読み取ってしまうこと。

<h3>・非リピータブルリードとは</h3>
　<b>非リピータブルリード</b>とは別の処理で<b>更新された値</b>が即座に反映されてしまうこと。例えば2回データを読み取る必要がある処理を行う際、1回目のデータが2回目のデータが異なるという不具合です。

<h3>・ファントムリードとは</h3>
　<b>ファントムリード</b>とは別の処理で<b>追加/削除された値</b>がすぐに反映されてしまうこと。例えば2回データを読み取る必要がある処理を行う際、1回目になかったデータが2回目に表れてしまうという不具合です。

<h2>・READ UNCOMMITTED</h2>
　<b>READ UNCOMMITTED</b>は分離性が一切ないレベルのことです。このレベルにおいてはロックがかけられていないのでデータの整合性は取りずらいですが、ロック待ちが起こらないので素早くデータのやり取りが行えるというメリットが存在します。これは書き込みしかしないログを記録するアプリやデータの更新頻度が低いアプリで使われます。
　このレベルでは先ほどのダーティーリード、非リピータブルリード、ファントムリードの<b>すべての不具合が起こってしまう</b>可能性があります。

<h2>・READ COMMITTED</h2>
　<b>READ COMMITTED</b>は、コミットしていないときは影響は及びませんが、コミットをしたときは別の処理に影響を及ぼしてしまいます。このレベルでは非リピータブルリード、ファントムリードの<b>２つの不具合</b>が起こってしまう可能性があります。

<h2>・REPEATABLE READ</h2>
　<b>REPEATABLE READ</b>とは、更新が別の処理でコミットされても分離性を保てる分離レベルです。MySQL(InnoDB)においては、Consistent reads(MVCC)という技術が使われるため、このレベルではファントムリードの<b>発生を抑えて</b>くれます。Consistent readsとはデータを読み取った際、そのデータを覚えることによって他の処理でデータが更新、追加された場合でも、１回目に読んだデータと違うという不具合が起きません。

<h2>・Serializable</h2>
　<b>Serializable</b>とはダーティーリード、非リピータブルリード、ファントムリードの<b>すべての不具合が起こる可能性がありません。</b>しかしデッドロックなどによってロック待ちが引き起こり、処理時間が長くなってしまう可能性が高くなります。

<h1>・ロックの範囲の種類</h1>
　ロックをかける範囲の種類には4つあります。1つ目は<b>レコードロック</b>です。レコードロックはその名の通り１つのレコードにロックをかけるもので、範囲が狭いものになります。<br>
　2つ目は<b>ギャップロック</b>です。ギャップロックは、指定した範囲にロックをかけるもので、WHERE文で指定した範囲をロックするものです。<br>
　3つ目は<b>ネクストキーロック</b>です。これは指定されている範囲(ギャップロックの範囲)に加えて、範囲＋１のキーのロックをするというものです。この番号をロックしたってことは次のこの番号も使うでしょといってロックをかけるものです。<br>
　最後は<b>空振りロック</b>で、存在しないキーのロックをしてしまうものです。存在しないキーのロックをしてしまうと処理が永遠に終わらない判定となり、ロックが終了せずデッドロックを引き起こす原因となってしまいます。これを引き起こさないためには、予めDELETE文やUPDATE文を発行する際、<b>対象となっているキーが存在するかを確認すること</b>が重要になります。

<h1>・まとめ</h1>
　このようにロックとは<b>「データの整合性を保つためにアクセスの制限をすること」</b>であり、ロックには<b>共有ロック</b>と<b>排他ロック</b>の２種類存在します。<br>
　そしてロックの影響の度合いを表す<b>トランザクション分離レベル</b>とそれぞれのレベルで引き起こされる不具合である<b>ダーティーリード、非リピータブルリード、ファントムリード</b>の3種類あります。