1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

トランザクション(MySQL)

1
Posted at

📅 note公開日:2025-08-02 10:34
🔁 この記事はnoteで公開していた内容をQiitaへ移行・再掲したものです。(必要に応じて加筆修正しています)

今回はトランザクションについての備忘録です。


内容

  • トランザクションとは?
  • なんのためにある?
  • トランザクションの使い方
  • 同時実行制御
  • ACID特性
  • ロック、ロックの確認
  • 使用したSQL文

トランザクションとは?

複数のSQL文によるデータ更新を、1つの処理単位として扱う仕組みのこと。
これにより、一連の処理が 「すべて成功」 or 「すべて失敗」 のどちらかになり、データの整合性を保てます。

言い換えると、トランザクションは これ以上分解できない作業の単位 と言えます。

参考(Progate):トランザクション

https://app.path.progate.com/articles/transaction

変更確定を COMMIT、変更取り消しを ROLLBACK と言います。


なんのためにある?

主にこの3つ。

  1. 途中で失敗しても元の状態に戻せる
  2. 同時に複数人が操作してもデータが壊れないようにする
  3. 「ひとかたまりの処理」として扱える

たとえばこんな場面

ECサイトの購入処理

処理 SQL
商品の在庫を減らす UPDATE
注文情報を記録する INSERT
顧客の購入履歴を更新する UPDATE

銀行口座の送金処理

処理 SQL
送金元の口座からお金を減らす UPDATE
送金先の口座にお金を追加する UPDATE

在庫管理システム

処理 SQL
入荷処理で在庫数を増やす UPDATE
出荷処理で在庫数を減らす UPDATE
在庫アラートの閾値をチェックする SELECT

閾値:ある基準や限界値(IT業界でよく出る用語)


トランザクションの使い方

ポイントはこの3つ。

  1. START TRANSACTION;COMMIT; に挟まれた処理がトランザクション対象
  2. COMMIT; で確定(保存)
  3. 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さんが終わるまで待つ


ロックの確認(実験)

手順

  1. ターミナルを2つ開き、両方とも employees DB に接続
  2. ターミナル1でトランザクション開始 → salaryを70000に更新
  3. ターミナル2で同じ行を更新(2倍)しようとする
  4. ターミナル1でSELECTして、70000のままロックされていることを確認
  5. ターミナル1でCOMMIT
  6. ターミナル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 TRANSACTIONCOMMIT で確定、問題があれば ROLLBACK で取り消し
  • 同時実行制御により、複数人操作でもデータが壊れにくい
  • トランザクションが安全に動くための約束が ACID(原子性・一貫性・独立性・永続性)
  • ロックは「他の処理に触らせない鍵」で、更新競合を防ぐ動きが確認できる
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?