diff --git a/src/database/overview/README.md b/src/database/overview/README.md index d0f8536b..a01d6235 100644 --- a/src/database/overview/README.md +++ b/src/database/overview/README.md @@ -1,13 +1,13 @@ # データベース Overview Webアプリケーション開発において、取得したデータを適切に保存し、必要なデータを適切に取り出して利用しなければならない場面はよくあります。データベースは、そうした場面で非常に有用な技術ですが、データを適切に取り扱うためにはデータベースがどのようなことに配慮して作られているか理解する必要があります。このOverviewでは、データベースに関する基本的な仕組みについて取り扱います。 -# データベースとは +## データベースとは 1. データの集合体 * 事前に決めたルールに従って保存されたデータの集合体のこと 2. DBMS(Database Management System) * DBMSはいわゆるDB製品とほぼ同義と考えても良い -# DBMSが備える3つの主要機能 +## DBMSが備える3つの主要機能 DBMS(Database Management System)は、基本的に以下の3つの機能を備えている 1. データの管理 @@ -17,7 +17,7 @@ DBMS(Database Management System)は、基本的に以下の3つの機能を備 3. トランザクション管理 * 新たなデータを挿入したり、不要なデータを削除したりするなど、データ操作を行う場合に、どのように読み書きを制御するか -# データベースの種類とデータ管理方法の違い +## データベースの種類とデータ管理方法の違い データベースは製品設計の考え方の違いにより、データの管理方法が複数存在する 1. リレーショナルデータベース @@ -36,7 +36,7 @@ DBMS(Database Management System)は、基本的に以下の3つの機能を備 上記1以外は、リレーショナルデータベースではないことから、[NoSQL](https://ja.wikipedia.org/wiki/NoSQL)と呼ばれることもある -# データへのアクセス手段 +## データへのアクセス手段 1. リレーショナルデータベース * SQL * SQLには、ANSI/ISOで決められた標準SQLと呼ばれるものがある。標準SQLは、決められた年をつけて表記され、現在の最新は「SQL:2016」 @@ -47,13 +47,13 @@ DBMS(Database Management System)は、基本的に以下の3つの機能を備 SQLを使うリレーショナルデータベースであっても差異があることが多く、非リレーショナルデータベース(NoSQL)は独自クエリになるため、アプリケーションのバックエンドに利用するデータベースをアプリケーション構築後に別のデータベースに移行するのは容易ではない。そのため、バックエンドに利用するデータベース選定は慎重に検討する必要がある。 -# トランザクションとは +## トランザクションとは アプリケーションが意味のある処理を実行する際に必要な複数のデータベースへの処理単位 * 例えば、AさんからBさんに10万円を送金する処理は、Aさんの口座から10万円減額し、Bさんの口座を10万円増額する、という全ての処理が完了しないと「送金」という意図した操作が成立しない。 * トランザクションは、意図した操作を成立させるために必要な複数の処理を束ねたような概念。 -# トランザクションとACID特性 +## トランザクションとACID特性 トランザクションの中でも、特にお金の処理などビジネスデータを扱う場合、データ不整合やデータ消失を起こすと重大な事故になってしまう。そうしたことが起きないように、トランザクションでは以下の4つの性質が保証されるべきとされている。 * **A**tomicity(原子性) @@ -73,7 +73,7 @@ ACID特性は、上記の4つの特性の英単語の頭文字から作られた * 非リレーショナルデータベース(NoSQL)は、リレーショナルデータベースに比べて、大規模データを高速に処理することができると言われるが、NoSQLがACID特性の一部を緩めることで、大規模データの処理性能を効率的に実施している部分がある。アプリケーション開発者は、アプリケーションで扱うデータを守る上で、ACID特性の一部が緩められていても問題がないか検討し、必要であれば保証されていない特性をアプリケーション側で補う必要があるが、考慮する必要性が無ければ、ACID特性を緩めることで、高速性等の恩恵を受けることができる。 -# 原子性(Atomicity)とは +## 原子性(Atomicity)とは * 例: AさんからBさんに10万円送金する場合 1. Aさんの口座を10万円減額する @@ -91,7 +91,7 @@ ACID特性は、上記の4つの特性の英単語の頭文字から作られた トランザクション内で実行してきた処理を全て破棄し、トランザクション開始時点の状態に戻すこと -# 一貫性・整合性(Consistency)とは +## 一貫性・整合性(Consistency)とは * 例: 口座の金額は0円以上である 仮に、残高が5千円の口座から、1万円の引落を実行した場合、口座残高はマイナス5千円となり、「口座の金額は0円以上である」というルールに違反することになるため、このケースでは1万円の引落の処理は、データベース側でブロックされ実行されない @@ -107,37 +107,50 @@ ACID特性は、上記の4つの特性の英単語の頭文字から作られた UNIQUE制約を設定した列のデータは、必ず一意になる(その列のデータは列内で重複しないことを保証する) -# 独立性・分離性(Isolation)とは + テーブル内のレコードを一意に特定するために使われる主キー(Primary Key、PKと記載される)と言われるカラムは、NOT NULL制約とUNIQUE制約の2つの制約を設定することで実現されている + +## 独立性・分離性(Isolation)とは データベースは、組織内などで情報共有のために使われるため、同時に複数のアクセス(トランザクション)を処理する必要がある。独立性・分離性は、複数トランザクションを同時実行しても、複数トランザクションを1つずつ逐次実行した時と同じ結果になるように保証する特性。 -## ロック(lock)とは +### ロック(lock)とは 複数のトランザクションを同時実行する際に、処理対象データが他のトランザクションの影響を受けないよう、処理に必要になる期間データを占有する機能。独立性・分離性を保証する上で必要な機能の1つ。 * 例: AさんからBさんに10万円送金する処理(トランザクション1)と、BさんからCさんに5万円送金する処理(トランザクション2)を同時実行する場合 1. トランザクション1がAさんの口座をロックし10万円減額し20万円にする +
![lock_01](./image/lock_01.svg) 2. トランザクション2がBさんの口座をロックし5万円減額し15万円にする +
![lock_02](./image/lock_02.svg) 3. トランザクション1がBさんの口座を10万増額しようとするが、トランザクション2が口座をロック中のため待機 +
![lock_03](./image/lock_03.svg) 4. トランザクション2がCさんの口座をロックし5万円増額し10万円にする +
![lock_04](./image/lock_04.svg) 5. トランザクション2が処理結果を保存し、BさんとCさんの口座ロックを解除する +
![lock_05](./image/lock_05.svg) 6. トランザクション1がBさんの口座をロックし10万増額し25万円にする +
![lock_06](./image/lock_06.svg) 7. トランザクション1が処理結果を保存し、AさんとBさんの口座ロックを解除する +
![lock_07](./image/lock_07.svg) 上記例の場合、Bさんの口座は、5万円の減額処理と10万円の増額処理が競合したが、トランザクション2がBさんの口座を2の時点でロックするため、トランザクション2 → トランザクション1の順番で処理が実施される。この結果は、トランザクション1を先に全て実行し、その後トランザクション2を実行した場合と同じになるので、独立性・分離性が担保できている。 -## デッドロック(deadlock)とは +### デッドロック(deadlock)とは デッドロックとは、お互いのロック解除を待つことでお互いの処理が永久に進まなくなる状態のこと。例えば、トランザクション1がトランザクション2のロック解除を待ち、トランザクション2がトランザクション1のロック解除を待ってしまう様な状態になると、トランザクション1もトランザクション2も処理が完了せずロック解除に至らないため、ロックが永久に解除されず処理が永久に終了しなくなってしまう。 * 例: AさんがBさんに10万円送金する処理(トランザクション1)と、BさんがAさんに5万円送金する処理(トランザクション2)を同時実行する場合 1. トランザクション1がAさんの口座をロックし10万円減額し20万円にする +
![dead_lock_01](./image/dead_lock_01.svg) 2. トランザクション2がBさんの口座をロックし5万円減額し15万円にする +
![dead_lock_02](./image/dead_lock_02.svg) 3. トランザクション1がBさんの口座を10万増額しようとするが、トランザクション2が口座をロック中のため待機 +
![dead_lock_03](./image/dead_lock_03.svg) 4. トランザクション2がAさんの口座を5万増額しようとするが、トランザクション1が口座をロック中のため待機 +
![dead_lock_04](./image/dead_lock_04.svg) 上記例は、トランザクション1はBさんの口座のロック解除を待つ必要があるが、それにはトランザクション2が終了する必要があり、トランザクション2はAさんの口座のロック解除を待つしか無いが、それにはトランザクション1が終了する必要があり、処理が永久に進まなくなる。そのため、データベースには、デッドロック状態を検知し、デッドロックとなったトランザクションの片方を強制中断させることで、デッドロックを解消する機能が備えられている。 デッドロックによって強制中断したトランザクションは、データベースによって再度トランザクションが実行されることはないので、アプリケーション側でデッドロックによる中断を検知したらトランザクションを再実行する必要がある。デッドロックは、複数トランザクションを同時実行するのであれば必ず発生するため、アプリケーション作成時にデッドロックが起きる想定で設計しておく必要がある。 -## 分離レベル(isolation level)とは +### 分離レベル(isolation level)とは トランザクション間の分離・独立性をどのぐらい緩めるか4段階で定義したもの。 |分離レベルの名称|分離レベルの詳細|ダーティーリード|ノンリピータブルリード|ファンタムリード| @@ -170,7 +183,7 @@ SERIALIZABLE以外の分離レベルでは、分離性・独立性を緩める 高い分離レベルを実現するためには、ロックをかけてデータを保護するため必要があるため、同時実行速度が犠牲になる。一方で低い分離レベルは、ロックをかける必要がなくなるため、同時実行時の速度が向上する。データベース製品ごとにどのように分離レベルが実装されているかを理解しつつ、上記のような現象が発生するリスクを許容できるかアプリケーション設計者がよく検討した上で、データの安全性よりも実行速度を重視したい場合、分離レベルを低くすることも1つの選択肢になる。 -# 永続性(Durability)とは +## 永続性(Durability)とは 永続性とは、トランザクションが確定(コミット)したら、それ以降にデータが失われないように保証する特性。 トランザクションにおいて、処理が全て完了し確定(コミット)する場合、確定(コミット)が成功したら、それ以降は確定されたデータは永久に消えない状態になっている必要がある。 @@ -179,13 +192,13 @@ SERIALIZABLE以外の分離レベルでは、分離性・独立性を緩める 仮に、確定(コミット)が成功したかの根拠となるデータの書き込み成功が、OSが用意しているキャッシュ(揮発性メモリー)領域への書き込みだった場合、電源断などの障害によってデータが消失する可能性があり、永続性の原則に違反する状況が発生してしまう。データベースでは、こうした状況を防ぐため確定(コミット)する際に、OSのキャッシュ領域ではなく、永続ディスクへの書き込みになるように制御するような機能が備わっている。 -# まとめ +## まとめ -## データを扱うことの難しさを知る +### データを扱うことの難しさを知る データを確実に保存し、必要な場面で確実に利用するためには、様々なことに注意を払う必要があります。アプリケーション開発者は、これまで見てきたようなデータに関して起きうる全ての状況を想定しながら、アプリケーションの設計・実装していく必要がありますが、データに関して起きうる全ての事象に対応したアプリケーションを1から実装するのは非現実的です(いわゆる[車輪の再発明](https://ja.wikipedia.org/wiki/%E8%BB%8A%E8%BC%AA%E3%81%AE%E5%86%8D%E7%99%BA%E6%98%8E))。 -## データベースを学び利用する +### データベースを学び利用する データベースを学ぶことは、データを扱う上で起きうる事象を学ぶことができ、アプリケーション開発の中でデータを扱う際に何に配慮すれば良いか見えて来ると思います。また、データベースを利用することで、データを扱う上で起きうる事象への配慮をデータベースに任せることができれば、アプリケーション開発者はアプリケーションに求められる本質的な機能の実装に集中でき、より良いアプリケーション開発を行うことができるようになると思います。 -## 必要な機能を備えたデータベース製品を選定する -昨今、様々なデータベース製品がリリースされています。それらの製品ごとにメリット・デメリット、得意・不得意な領域が存在します。データの安全性を重視するのか、それとも速度を重視するかなど、アプリケーションごとにデータに対する要求の方向性は変わってきますが、求める方向性に合致するデータベース製品を選定できるようになるためにも、データベースの知識を持つことが重要だと思います。 +### 必要な機能を備えたデータベース製品を選定する +昨今、様々なデータベース製品がリリースされています。それらの製品ごとにメリット・デメリット、得意・不得意な領域が存在します。データの安全性を重視するのか、それとも速度を重視するかなど、アプリケーションごとにデータに対する要求の方向性は変わってきますが、求める方向性に合致するデータベース製品を選定できるようになるためにも、データベースの知識を持つことが重要だと思います。 \ No newline at end of file diff --git a/src/database/overview/image/dead_lock_01.svg b/src/database/overview/image/dead_lock_01.svg new file mode 100644 index 00000000..3da905c1 --- /dev/null +++ b/src/database/overview/image/dead_lock_01.svg @@ -0,0 +1,48 @@ + +

30万円 → 20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

20万円

+
+

Bさんの口座

+
+

ロックなし

+
+

Tx1

10万円減額

 

+
\ No newline at end of file diff --git a/src/database/overview/image/dead_lock_02.svg b/src/database/overview/image/dead_lock_02.svg new file mode 100644 index 00000000..c9a48c7b --- /dev/null +++ b/src/database/overview/image/dead_lock_02.svg @@ -0,0 +1,48 @@ + +

30万円 → 20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

20万円 → 15万円

+
+

Bさんの口座

+
+

ロック: Tx2

+
+

Tx2

5万円減額

 

+
\ No newline at end of file diff --git a/src/database/overview/image/dead_lock_03.svg b/src/database/overview/image/dead_lock_03.svg new file mode 100644 index 00000000..d80a7caa --- /dev/null +++ b/src/database/overview/image/dead_lock_03.svg @@ -0,0 +1,48 @@ + +

Tx1

10万円増額

 

+
+

30万円 → 20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

20万円 → 15万円

+
+

Bさんの口座

+
+

ロック: Tx2

+
\ No newline at end of file diff --git a/src/database/overview/image/dead_lock_04.svg b/src/database/overview/image/dead_lock_04.svg new file mode 100644 index 00000000..d538eb9b --- /dev/null +++ b/src/database/overview/image/dead_lock_04.svg @@ -0,0 +1,50 @@ + +

Tx1

10万円増額

 

+
+

30万円 → 20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

20万円 → 15万円

+
+

Bさんの口座

+
+

ロック: Tx2

+
+

Tx2

5万円増額

 

+
\ No newline at end of file diff --git a/src/database/overview/image/lock_01.svg b/src/database/overview/image/lock_01.svg new file mode 100644 index 00000000..195041b4 --- /dev/null +++ b/src/database/overview/image/lock_01.svg @@ -0,0 +1,54 @@ + +

30万円 → 20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

20万円

+
+

Bさんの口座

+
+

ロックなし

+
+

5万円

+
+

Cさんの口座

+
+

ロックなし

+
+

Tx1

10万円減額

 

+
\ No newline at end of file diff --git a/src/database/overview/image/lock_02.svg b/src/database/overview/image/lock_02.svg new file mode 100644 index 00000000..a1da3fc5 --- /dev/null +++ b/src/database/overview/image/lock_02.svg @@ -0,0 +1,54 @@ + +

30万円 → 20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

20万円 → 15万円

+
+

Bさんの口座

+
+

ロック: Tx2

+
+

5万円

+
+

Cさんの口座

+
+

ロックなし

+
+

Tx2

5万円減額

 

+
\ No newline at end of file diff --git a/src/database/overview/image/lock_03.svg b/src/database/overview/image/lock_03.svg new file mode 100644 index 00000000..699cadf6 --- /dev/null +++ b/src/database/overview/image/lock_03.svg @@ -0,0 +1,54 @@ + +

30万円 → 20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

20万円 → 15万円

+
+

Bさんの口座

+
+

ロック: Tx2

+
+

5万円

+
+

Cさんの口座

+
+

ロックなし

+
+

Tx1

10万円増額

 

+
\ No newline at end of file diff --git a/src/database/overview/image/lock_04.svg b/src/database/overview/image/lock_04.svg new file mode 100644 index 00000000..339dae27 --- /dev/null +++ b/src/database/overview/image/lock_04.svg @@ -0,0 +1,56 @@ + +

30万円 → 20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

20万円 → 15万円

+
+

Bさんの口座

+
+

ロック: Tx2

+
+

5万円 → 10万円

+
+

Cさんの口座

+
+

ロック: Tx2

+
+

Tx1

10万円増額

 

+
+

Tx2

5万円増額

 

+
\ No newline at end of file diff --git a/src/database/overview/image/lock_05.svg b/src/database/overview/image/lock_05.svg new file mode 100644 index 00000000..ea25f6a6 --- /dev/null +++ b/src/database/overview/image/lock_05.svg @@ -0,0 +1,54 @@ + +

30万円 → 20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

15万円

+
+

Bさんの口座

+
+

ロックなし

+
+

10万円

+
+

Cさんの口座

+
+

ロックなし

+
+

Tx1

10万円増額

 

+
\ No newline at end of file diff --git a/src/database/overview/image/lock_06.svg b/src/database/overview/image/lock_06.svg new file mode 100644 index 00000000..7f300cae --- /dev/null +++ b/src/database/overview/image/lock_06.svg @@ -0,0 +1,54 @@ + +

30万円20万円

+
+

Aさんの口座

+
+

ロック: Tx1

+
+

15万円 → 25万円

+
+

Bさんの口座

+
+

ロック: Tx1

+
+

10万円

+
+

Cさんの口座

+
+

ロックなし

+
+

Tx1

10万円増額

 

+
\ No newline at end of file diff --git a/src/database/overview/image/lock_07.svg b/src/database/overview/image/lock_07.svg new file mode 100644 index 00000000..80e06fbe --- /dev/null +++ b/src/database/overview/image/lock_07.svg @@ -0,0 +1,52 @@ + +

20万円

+
+

Aさんの口座

+
+

ロックなし

+
+

25万円

+
+

Bさんの口座

+
+

ロックなし

+
+

10万円

+
+

Cさんの口座

+
+

ロックなし

+
\ No newline at end of file