SQLの基礎【トランザクションについて】

# 概要
今回はトランザクションについてまとめていく。

# トランザクションとは
トランザクションとは、sqlにおける一連のデータ更新処理の単位のことである。
複数のINSERT文、UPDATE文,DELETE文を連続して実行し、それらのクエリを一つの塊として管理する必要がある時がある。
(migration, dunpなど)
SQLでは、このような関連性のある複数のデータ更新処理を1つの単位にまとめて管理することが可能であり、その処理単位をトランザクションという。

# トランザクションの重要性
トランザクションが重要な場面は、複数の更新処理を連続して行う際に、全ての更新処理が成功しなければデータベースに更新をかけないようなシーンである。(逆にいうと、一つでも処理に失敗したらNGとすべきシーン)
トランザクションでは、何かが原因で一部の処理が失敗した場合に、ロールバックを実行して処理全体をリセットすることができる。

# トランザクションの特性(ACID特性)
トランザクション処理に求められる4つの特性が標準規格によって決められており、その頭文字をとった総称として「ACID特性」と呼ばれている。

## 原子性(Atomicity)
トランザクション処理は全て処理されるか、されないかのどちらかであるという特性。つまり、一部の処理がデータベースに反映されることがなくなる。

## 一貫性(Consistency)
トランザクションが途中で実行エラーとなった場合でも、トランザクションを開始する前の状態に戻すことで実行結果に矛盾がなくなり、データの整合性が保たれるという特性。一部のデータが更新され、その他のデータが更新されている状態はないということである。

## 独立性(Isolation)
トランザクションを複数実行している場合でも、ほかのトランザクションの影響を受けず実行結果は単一で実行した結果と同じ結果が返ってくるという特性。他のトランザクションでデータの更新があった場合にも影響を受けないということである。

## 永続性(Durability)
トランザクションの実行終了後、その実行結果が失われることはないという特性。ハードウェアに障害が発生した場合でも、保持していたログからトランザクション結果を復旧させるため、更新内容は保証される。

## 動作例
MySQLでトランザクションを試してみる。

```sql
-- テーブル作成
CREATE TABLE books (
id VARCHAR(20) PRIMARY KEY,
title VARCHAR(100),
price INTEGER NOT NULL
)
;

-- データ投入
INSERT INTO books(id,title,price) VALUES('00001','AWS基礎テキスト',3300);
INSERT INTO books(id,title,price) VALUES('00002','SQL基礎テキスト',2300);
INSERT INTO books(id,title,price) VALUES('00003','Java基礎テキスト',1100);
INSERT INTO books(id,title,price) VALUES('00004','PHP基礎テキスト',2100);
INSERT INTO books(id,title,price) VALUES('00005','NW基礎テキスト',1600);
```

実際のトランザクション処理の流れは以下である。
トランザクションを開始するには、`START TRANSACTION`コマンドまたは`BEGIN`コマンド、ロールバックしてDBへの処理の反映を取り消すには`ROLLBACK`コマンド、コミットしてDBに処理を反映するには`COMMIT`コマンドを使用する。
今回は、上記のテーブルに以下のレコードを追加するトランザクション処理を試す。


まず、現在のテーブルの中身を確認する。

```sql
SELECT * FROM books;
```
結果は以下である。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251807/b2127509-99b0-9f63-ceb5-0be9d23df1e3.png" width=300>

ここから実際にトランザクション処理を開始する。

```sql
BEGIN;
INSERT INTO books(id,title,price) VALUES('00006','Linux基礎テキスト',2000);
```

もう一度SELECT文を実行するとデータが追加されていることが確認できる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251807/eab2ee68-4d5c-6ba8-7a09-bdd80fcca628.png" width=300>

ここで、データの登録を取り消してみる。
ロールバックを使ってトランザクション処理の開始前の状態に戻す。

```sql
ROLLBACK;
```
検索すると、登録処理が反映されていない状態、トランザクション処理の開始前の状態に戻ったことが確認できる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251807/f54fc638-2673-5224-845b-a38c6947124e.png" width=300>

次は、逆にテーブルのデータを削除してロールバックをした場合を見てみる。

```sql
BEGIN;
DELETE FROM books;
```
ここで検索してもデータが入ってないというログが出力される。
ここでロールバックをするとトランザクション処理の開始前の状態に戻る。

```sql
ROLLBACK;
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251807/64547884-1840-ec7a-160a-2f7400b413f6.png" width=300>
データが元に戻っていることが確認できる。

最後にデータの登録処理を確定させてみる。
コミットしたあとでロールバックをしてもデータが登録されていることを確認する。

```sql
BEGIN;
INSERT INTO books(id,title,price) VALUES('00006','Linux基礎テキスト',2000);
COMMIT;
-- データの登録処理確定後のロールバック
ROLLBACK;
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251807/2eea1710-39ff-a09b-6ab7-3a098ad7c30f.png" width=300>

ロールバックをしてもデータが登録されたままの状態が確認できる。

# 参考
データベースさわったこと無い新人向けトランザクション入門 : https://qiita.com/komattio/items/838ea5df68eb076e8099
トランザクションで処理をコントロールする : https://sql55.com/t-sql/transactions.php
トランザクション処理 : http://se-java-school.com/itstudy/database/intro_db_jdbc/sqltext_06.php#Section1_02
MySQL公式 ： https://dev.mysql.com/doc/refman/5.6/ja/commit.html