> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL の COMMIT と ROLLBACK

> START TRANSACTION、COMMIT、および ROLLBACK によって複数の MySQL 文がまとめて成功または失敗する仕組み、および確認なしに作業をコミットする文。

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

2 つの口座の間でお金を移動するには 2 つの文が必要で、その間で失敗すると
お金はどこにも残りません。トランザクションは文をまとめ、すべてが有効になるか、
どれも有効にならないかのどちらかにします。

これらの例は、[INSERT](https://villagesql.com/docs/ja/tutorial/insert.md) の `sakila_practice` データベースを
使います。始める前にそこにあるセットアップのブロックをもう一度実行し、次に
`mysql -u root -p sakila_practice` でクライアントを開いてください。

## トランザクションの仕組み

```sql theme={null}
START TRANSACTION;
FIRST_STATEMENT;
SECOND_STATEMENT;
COMMIT;
```

`FIRST_STATEMENT` と `SECOND_STATEMENT` を、一緒に成功しなければならない文に
置き換えます。

`COMMIT` は作業を永続化し、他の全員から見えるようにします。`ROLLBACK` は作業を
捨て、行を元のとおりに戻します。この 2 つのどちらかを入力するまで、変更は
あなただけのものです。別のセッションにはまだ古い値が見えています。

トランザクションの外にあるすべての文は、それ自体でコミットします。`autocommit`
がオンだからです。

```sql theme={null}
SELECT @@autocommit AS autocommit;
```

```text theme={null}
+------------+
| autocommit |
+------------+
|          1 |
+------------+
1 row in set (0.00 sec)
```

これまでのレッスンで `COMMIT` が必要なかったのはそのためです。各 `INSERT` と
`UPDATE` は 1 文のトランザクションでした。`START TRANSACTION` は、あなたが
終えるまでそれを保留します。

## 例

### ROLLBACK で作業を取り消す

```sql theme={null}
SELECT * FROM account;
```

```text theme={null}
+------------+------------------+---------+
| account_id | owner            | balance |
+------------+------------------+---------+
|          1 | Mary Smith       |  500.00 |
|          2 | Patricia Johnson |  250.00 |
+------------+------------------+---------+
2 rows in set (0.00 sec)
```

Mary から Patricia へ 100 を移動し、結果を見て、それから気が変わったとします。

```sql theme={null}
START TRANSACTION;
UPDATE account SET balance = balance - 100 WHERE account_id = 1;
UPDATE account SET balance = balance + 100 WHERE account_id = 2;
SELECT * FROM account;
ROLLBACK;
```

```text theme={null}
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

+------------+------------------+---------+
| account_id | owner            | balance |
+------------+------------------+---------+
|          1 | Mary Smith       |  400.00 |
|          2 | Patricia Johnson |  350.00 |
+------------+------------------+---------+
2 rows in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)
```

トランザクション内の `SELECT` は 400 と 350 を報告します。セッションは自分の
コミットされていない作業を見るためです。その後の `ROLLBACK` が両方の更新を
取り消します。

```sql theme={null}
SELECT * FROM account;
```

```text theme={null}
+------------+------------------+---------+
| account_id | owner            | balance |
+------------+------------------+---------+
|          1 | Mary Smith       |  500.00 |
|          2 | Patricia Johnson |  250.00 |
+------------+------------------+---------+
2 rows in set (0.00 sec)
```

これが MySQL に唯一ある取り消しです。トランザクションの外で文が実行されて
しまうと、古い値は失われます。

### COMMIT で作業を保持する

```sql theme={null}
START TRANSACTION;
UPDATE account SET balance = balance - 100 WHERE account_id = 1;
UPDATE account SET balance = balance + 100 WHERE account_id = 2;
COMMIT;
```

```text theme={null}
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Query OK, 0 rows affected (0.00 sec)
```

```sql theme={null}
SELECT * FROM account;
```

```text theme={null}
+------------+------------------+---------+
| account_id | owner            | balance |
+------------+------------------+---------+
|          1 | Mary Smith       |  400.00 |
|          2 | Patricia Johnson |  350.00 |
+------------+------------------+---------+
2 rows in set (0.00 sec)
```

2 つの更新は一緒に反映されました。400 と 250 を同時に見た他のセッションは 1 つも
なく、それがこのように書く理由のすべてです。

## 頼まれなくてもコミットする文がある

データベースの形を変える文はロールバックできません。さらに悪いことに、そうした
文を実行すると、開いているトランザクションがその時点までに行ったことがコミット
されます。

```sql theme={null}
START TRANSACTION;
UPDATE account SET balance = 0 WHERE account_id = 1;
CREATE TABLE note (id INT);
ROLLBACK;
```

```text theme={null}
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)
```

`ROLLBACK` を含め、すべての行が成功を報告します。

```sql theme={null}
SELECT * FROM account;
```

```text theme={null}
+------------+------------------+---------+
| account_id | owner            | balance |
+------------+------------------+---------+
|          1 | Mary Smith       |    0.00 |
|          2 | Patricia Johnson |  350.00 |
+------------+------------------+---------+
2 rows in set (0.00 sec)
```

残高は 0 です。`CREATE TABLE` は自身の実行前に更新をコミットしたため、
`ROLLBACK` には取り消すものが残っておらず、それでも成功を報告しました。
`ALTER TABLE`、`DROP TABLE`、`TRUNCATE TABLE`、および `RENAME TABLE` も同じ
ように振る舞います。データを守っているトランザクションからは、この 5 つを
すべて外してください。

一時テーブルは例外です。`CREATE TEMPORARY TABLE` と `DROP TEMPORARY TABLE` は
何もコミットしないため、途中に一時テーブルを置いた同じテストでは、残高は
500.00 のままです。

## まとめ

* `START TRANSACTION`、次に文、次に `COMMIT` または `ROLLBACK` と書きます。
* トランザクションの外にあるすべての文は、それ自体でコミットすると考えてください。`autocommit` がオンだからです。
* 自分のセッションは自身のコミットされていない変更を見るが、他のセッションはそれを見ないと考えてください。
* `ROLLBACK` を唯一の取り消しとして扱います。
* `CREATE TABLE`、`ALTER TABLE`、`DROP TABLE`、`TRUNCATE TABLE`、および `RENAME TABLE` はトランザクションから外します。それぞれがトランザクションをコミットするためです。
* `CREATE` と `DROP` の `TEMPORARY` 形は何もコミットしないと考えてください。

## 関連項目

* [UPDATE](https://villagesql.com/docs/ja/tutorial/update.md) — トランザクションで包む価値が最も高い文
* [DELETE](https://villagesql.com/docs/ja/tutorial/delete.md) — 取り戻したくなるかもしれない行の削除
* [MySQL のトランザクション](https://villagesql.com/docs/ja/guides/transactions.md) — 分離レベル、ロック、およびそのコスト
* [MySQL のデッドロック](https://villagesql.com/docs/ja/guides/deadlocks.md) — 2 つのトランザクションが同じ行を求めたときに起きること


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.