📅 note公開日:2025-08-02 10:34
🔁 この記事はnoteで公開していた内容をQiitaへ移行・再掲したものです。(必要に応じて加筆修正しています)
今回はトランザクションについての備忘録です。
内容
- トランザクションとは?
- なんのためにある?
- トランザクションの使い方
- 同時実行制御
- ACID特性
- ロック、ロックの確認
- 使用したSQL文
トランザクションとは?
複数のSQL文によるデータ更新を、1つの処理単位として扱う仕組みのこと。
これにより、一連の処理が 「すべて成功」 or 「すべて失敗」 のどちらかになり、データの整合性を保てます。
言い換えると、トランザクションは これ以上分解できない作業の単位 と言えます。
参考(Progate):トランザクション
https://app.path.progate.com/articles/transaction
変更確定を COMMIT、変更取り消しを ROLLBACK と言います。
なんのためにある?
主にこの3つ。
- 途中で失敗しても元の状態に戻せる
- 同時に複数人が操作してもデータが壊れないようにする
- 「ひとかたまりの処理」として扱える
たとえばこんな場面
ECサイトの購入処理
| 処理 | SQL |
|---|---|
| 商品の在庫を減らす | UPDATE |
| 注文情報を記録する | INSERT |
| 顧客の購入履歴を更新する | UPDATE |
銀行口座の送金処理
| 処理 | SQL |
|---|---|
| 送金元の口座からお金を減らす | UPDATE |
| 送金先の口座にお金を追加する | UPDATE |
在庫管理システム
| 処理 | SQL |
|---|---|
| 入荷処理で在庫数を増やす | UPDATE |
| 出荷処理で在庫数を減らす | UPDATE |
| 在庫アラートの閾値をチェックする | SELECT |
※ 閾値:ある基準や限界値(IT業界でよく出る用語)
トランザクションの使い方
ポイントはこの3つ。
-
START TRANSACTION;とCOMMIT;に挟まれた処理がトランザクション対象 COMMIT;で確定(保存)ROLLBACK;で取り消し(元に戻す)
例
START TRANSACTION; -- トランザクション開始
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
COMMIT; -- 問題なければ確定(変更が保存される)
問題があればこちら:
ROLLBACK; -- 元に戻す
同時実行制御
複数の人(処理)が同時にトランザクションを動かしても、データがおかしくならないようにする仕組みのこと。
例:銀行口座で、複数人が同時に入金・出金処理をした場合でも、整合性が崩れないように制御する。
ACID特性
ACID特性とは、トランザクションが安全に・正しく行われるための4つの約束(ルール) 🤞
Atomicity(原子性)
処理は 全部成功するか、全くしないか のどちらか。
「全部成功しないなら、最初から無かったことにしなさい!」
例:Aさんから出金 → Bさんへ振込、途中で失敗
→ この一連を最初から無かったことにする
Consistency(一貫性)
データのルール・つながり・意味を必ず守る。
「つじつまが合っている」状態を保つ。
例:在庫がマイナス、年齢が100歳、小学生の年齢が異常値…など
Isolation(独立性 / 分離性)
同時に複数人が操作しても、処理結果がぶつからないように見えること。
例:Isolationのないコンビニ
→ 全員の会計を同時に打つのでレシートがぐちゃぐちゃ
Isolationがあるコンビニ
→ 1人目が終わってから次の人(少なくとも「独立しているように見える」)
Durability(永続性)
一度完了(COMMIT)した処理は、障害が起きても消えない。
例:注文完了直後にサーバーがクラッシュ
→ 完了したトランザクションは記録に残る
ロック
ロックとは、データを他人に勝手に触らせないように鍵をかけること。
「使用中」の看板を立てるイメージ。
例:Aさんが在庫を減らす処理中
→ Bさんが同じ商品にアクセスしようとしても、Aさんが終わるまで待つ
ロックの確認(実験)
手順
- ターミナルを2つ開き、両方とも employees DB に接続
- ターミナル1でトランザクション開始 → salaryを70000に更新
- ターミナル2で同じ行を更新(2倍)しようとする
- ターミナル1でSELECTして、70000のままロックされていることを確認
- ターミナル1でCOMMIT
- ターミナル2で更新が通り、給与が2倍になっているはず
ターミナル1
※ロック検証としては、本来 START TRANSACTION; を入れてから更新するのが分かりやすいです(※後述)。
$ mysql -u root
mysql> UPDATE salaries
-> SET salary = 70000
-> WHERE emp_no = 10001 AND from_date = '1986-06-26';
Query OK, 1 row affected (0.018 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT salary
-> FROM salaries
-> WHERE emp_no = 10001 AND from_date = '1986-06-26';
+--------+
| salary |
+--------+
| 70000 |
+--------+
1 row in set (0.002 sec)
mysql> COMMIT;
Query OK, 0 rows affected (0.007 sec)
ターミナル2
$ mysql -u root
mysql> UPDATE salaries
-> SET salary = 140000
-> WHERE emp_no = 10001 AND from_date = '1986-06-26';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
ロックは確認できたが、タイムアウトしてしまった💦
mysql> SELECT salary
-> FROM salaries
-> WHERE emp_no = 10001 AND from_date = '1986-06-26';
+--------+
| salary |
+--------+
| 70000 |
+--------+
1 row in set (0.001 sec)
⑥の確認ができないため、ROLLBACK → 再度実行
mysql> UPDATE salaries
-> SET salary = 140000
-> WHERE emp_no = 10001 AND from_date = '1986-06-26';
Query OK, 1 row affected (0.005 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT salary
-> FROM salaries
-> WHERE emp_no = 10001 AND from_date = '1986-06-26';
+--------+
| salary |
+--------+
| 140000 |
+--------+
1 row in set (0.001 sec)
補足(ロック検証をより確実にするなら)
ターミナル1側で最初にこれを入れると「トランザクション中のロック」が明確になります。
START TRANSACTION;
使用したSQL文
SELECT
SELECT カラム名
FROM テーブル名
WHERE 条件 AND 条件;
UPDATE
UPDATE テーブル名
SET カラム名 = 新しい値
WHERE 条件 AND 条件;
トランザクション
START TRANSACTION;
-- 指示出しSQL文
COMMIT;
ROLLBACK
ROLLBACK;
SHOW TABLES
mysql> SHOW TABLES;
+----------------------+
| Tables_in_employees |
+----------------------+
| current_dept_emp |
| departments |
| dept_emp |
| dept_emp_latest_date |
| dept_manager |
| employees |
| salaries |
| titles |
+----------------------+
8 rows in set (0.002 sec)
DESCRIBE(テーブル定義の確認)
※見出しが「DESCRIBE カラム名」になっていたので、意味が変わらない範囲で修正(DESCRIBE テーブル名)。
mysql> DESCRIBE salaries;
+-----------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------+------+-----+---------+-------+
| emp_no | int | NO | PRI | NULL | |
| salary | int | NO | | NULL | |
| from_date | date | NO | PRI | NULL | |
| to_date | date | NO | | NULL | |
+-----------+------+------+-----+---------+-------+
4 rows in set (0.002 sec)
まとめ(Conclusion)
- トランザクションは「複数SQLを1つの処理単位」にまとめて、整合性を守る仕組み
-
START TRANSACTION〜COMMITで確定、問題があればROLLBACKで取り消し - 同時実行制御により、複数人操作でもデータが壊れにくい
- トランザクションが安全に動くための約束が ACID(原子性・一貫性・独立性・永続性)
- ロックは「他の処理に触らせない鍵」で、更新競合を防ぐ動きが確認できる