🎯 はじめに
データベースの基礎について振り返りをしたので、振り返りも込めて、基礎をまとめました。
アプリ開発において、データベース設計はすべての土台です。UIやロジックは後からでも修正できますが、データ構造の欠陥は後戻りが難しい。
TechCampで初めてマイグレーションを扱ったとき、
「打ち間違い一つでデータが壊れる」「構造変更が大変」と痛感しました。
そして今では、こう思っています。
アプリで一番大切なのはデータベースだ。
なぜなら、アプリケーションはDBを中心に設計されており、リクエストとレスポンスの流れはすべて
「データを扱うため」
に存在しているからです。
つまり、DBがあるからこそ「アプリがアプリとして成立している」と思っています。
🧩 データベースとは何か?
データベース(DB)は、「情報を体系的に管理・保存・検索できるシステム」です。
アプリケーションのすべての情報の最終的な置き場になります。
例:
- ユーザー情報
- 投稿データ
- コメント履歴
- ログや設定情報
📘 テーブル・カラム・レコードの関係
| 要素 | 意味 | 例 |
|---|---|---|
| テーブル | データの集合体 | users |
| カラム | 各項目(属性) |
name, email, age
|
| レコード | 1件のデータ | ("Taro", "taro@example.com", 25) |
+-------------------------+
| users |
+----+----------+---------+
| id | name | email |
+----+----------+---------+
| 1 | Taro | ... |
| 2 | Hanako | ... |
+----+----------+---------+
⚙️ SQLとは?
SQL(Structured Query Language)は、DBと会話するための言語です。
主な操作は次の4つ。
| 操作 | コマンド例 | 説明 |
|---|---|---|
| SELECT | SELECT * FROM users; |
データの取得 |
| INSERT | INSERT INTO users (name) VALUES ('Taro'); |
データの登録 |
| UPDATE | UPDATE users SET name='Jiro' WHERE id=1; |
データの更新 |
| DELETE | DELETE FROM users WHERE id=1; |
データの削除 |
SQLは通常大文字で書く慣習があり、
命令の末尾には必ずセミコロン(;)を付けます。
💬 文字列・NULL・パラメータ
-
文字列:
'Taro'のようにシングルクオートで囲む -
NULL: 「値が存在しない」こと。
NOT NULL制約で空を禁止できる - パラメータ: アプリからSQLに値を渡す変数的な存在
SELECT * FROM users WHERE id = ?;
?の部分に値を埋め込む。これにより、SQLインジェクションも防止できる。
⚙️ トランザクションの基本構造
SQLでは、以下のように書きます:
BEGIN; -- トランザクション開始
UPDATE accounts SET balance = balance - 10000 WHERE name = 'Aさん';
UPDATE accounts SET balance = balance + 10000 WHERE name = 'Bさん';
COMMIT; -- 全部成功 → 確定
-- ROLLBACK; -- 途中失敗時 → 取り消し
トランザクションとは、
>一連の処理を「ひとまとめ」として扱う仕組み。
たとえば銀行振込のように
「Aからお金を引き落とし、Bに振り込む」
という2つの処理を同時に成功/同時に失敗させるのがトランザクションです。
🧱 トランザクションの性質(ACID特性)
信頼性を保証するための4つの柱があります。
| 特性 | 名称 | 説明 |
|---|---|---|
| A | Atomicity(原子性) | すべて成功 or すべて失敗。中途半端なし。 |
| C | Consistency(一貫性) | 処理前後でデータの整合性が保たれる。 |
| I | Isolation(独立性) | 同時実行でも干渉しないようにする。 |
| D | Durability(永続性) | COMMITした内容は電源が落ちても残る。 |
🔍 つまりトランザクションは、
「完全性を守るための安全装置」 と言えます。
もし途中でエラーが起きたら ROLLBACK で元に戻せます。
🔄 サブクエリと仮想テーブル
SQLではクエリの中に別のクエリを埋め込むことができます。
これをサブクエリと呼びます。
SELECT * FROM users
WHERE id IN (SELECT user_id FROM posts WHERE likes > 10);
内側の SELECT 結果を仮想テーブルとして扱い、
一時的な検索結果を利用できます。
ORM(オブジェクトリレーショナルマッパー)
コードからSQLを直接書かずにDBを操作できる仕組みが ORM です。
- Ruby → ActiveRecord
- PHP → Eloquent(Laravel)
- Python → SQLAlchemy
ActiveRecord例
User.create(name: "Taro", email: "t@example.com")
→ SQLの
INSERT INTO users ...が裏で自動実行されます
⚙️ なぜDB設計は慎重にすべきか
DB設計を誤ると、アプリ全体の整合性が崩れます。
一度本番に投入すると、変更は非常にリスクが高い。
| 問題点 | 内容 |
|---|---|
| データ消失 | ALTERやDROPで既存データが破損 |
| 外部キー整合性 | 関連テーブルまで修正が波及 |
| バックアップ運用 | 復旧コストが高い |
DBはROM的な存在であり、基本的に「参照中心」に設計すべきです。
むやみに書き換えることは、アプリの履歴や信頼性を壊します。
🧮 データの「形」を定義する
テーブル設計とは「データの形を決めること」。
型・制約・関係性を明確にすることで、アプリ全体が安定します。
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
age INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
🔗 リレーショナルの力:外部キーでつながる世界
RDB(リレーショナルデータベース)は、
テーブル同士の関連性を持てる点が最大の特徴です。
CREATE TABLE posts (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
content TEXT,
FOREIGN KEY (user_id) REFERENCES users(id)
);
user_id が外部キー。
これにより、ユーザーに紐づいた投稿を容易に検索できます。
SELECT * FROM posts
JOIN users ON users.id = posts.user_id;
まさに 「関係性こそがデータの命」。
🧠 所感:僕がDBを好きな理由
僕がデータベースを好きな理由は明確です。
アプリにおいて、最も本質的で、最も信頼できる存在がDBだからです。
リクエストが来て、レスポンスを返す。
その流れの中心に、必ず「データのやり取り」があります。
データベースがあるからこそ、
アプリはユーザー体験を“記録できる”プラットフォームになる。
もしデータを保持できなければ、
すべてのやり取りは一瞬で消え、ユーザー体験も残らない。
だからこそ、DBはアプリの大黒柱なのです。
🛡 SQLインジェクションはタワーディフェンスだ
SQLインジェクションとは、外部から悪意あるSQL文を埋め込まれる攻撃。
パラメータバインドを怠ると、攻撃者にクエリを乗っ取られる危険があります。
僕の感覚では、これはタワーディフェンスゲームに似ています。
-
データベースが「城」
-
パラメータバインドが「防壁」
-
攻撃者の入力が「敵」
防壁(プリペアドステートメント)を正しく築けば、
どんな攻撃も通さない。
設計の堅牢さがそのままセキュリティにつながるのです。
✅ まとめ
データベースはアプリの心臓部
設計を誤るとアプリ全体が崩壊する
NULL・外部キー・型制約を丁寧に定義する
SQLインジェクション対策は“防御設計”
DBがあるからこそ、アプリは存在できる