# 36강. 트랜잭션
여기에서는 트랜잭션에 대해서 알아본다.

**`트랜잭션의 제어`**
```
START TRANSACTION
COMMIT
ROLLBACK
```

![36강 트랜잭션](https://user-images.githubusercontent.com/68052095/102683892-6ae4e980-4217-11eb-80d6-d08853e61e89.jpg)

- 데이터베이스는 `트랙잭션`이라는 기능을 제공한다.
- `INSERT`나 `UPDATE` 명령으로 데이터를 추가, 갱신할 때도 트랜잭션 기능을 사용하지만 지금까지 특별히 의식할 필요는 없었다.
- 이는 자동 커밋이라 불리는 기능이 동작했기 때문이다.

---

## 1. 트랜잭션
정규화에 의해 분할된 주문 테이블과 주문상품 테이블의 관계를 생각해보자.

![36강 주문 테이블과 주문상품 테이블](https://user-images.githubusercontent.com/68052095/102683891-69b3bc80-4217-11eb-8d98-32d43cec813e.jpg)

- 주문 테이블과 주문상품 테이블 사이에는 의존관계가 존재한다.
- 주문 테이블에 행이 존재한다면 주문상품 테이블에는 적어도 하나의 행이 존재해야 한다.
- 그렇지 않으면 주문한 상품이 없는데도 주문이 된 상태가 된다.
- 보통은 하나 이상의 상품을 주문하므로 주문이 발생하면 주문 테이블과 주문상품 테이블 모두 행이 추가된다.
- 물론 있다, 없다는 주문번호와 관련이 있으므로 '같은 주문번호로'라는 조건을 붙일 수 있다.

### 발주처리
- 주문이 발생했을 때 어떻게 처리되는지 생각해보자. 간단히 말하자면 발주처리에 관한 것으로, 먼저 주문번호를 지정해야 한다.
- 이때 기존 주문과 구분되는 주문번호를 발행하는 처리가 필요하다.
- 자동 증가를 사용하면 자동적으로 번호가 부여되지만 그렇지 않은 경우에는 '번호 중 가장 큰 값을 `SELECT` 명령으로 가져와 그 값에 1을 더한다'라는 처리가 필요하다.
- 최대값은 `MAX()`로 검색할 수 있으므로 `MAX + 1`이라 할 수도 있다.
- 번호를 발행 받았다면 해당 번호를 키로 삼아 `INSERT`가 이루어진다.
- 주문 테이블에는 `INSERT` 한 번, 주문상품 테이블에는 주문된 상품 수만큼 `INSERT` 명령이 실행된다.
- 중요한 것은 복수의 테이블에 `INSERT` 되므로 실행되는 명령은 최소 두 번이라는 것이다.

**`발주처리`**
```
INSERT INTO 주문 VALUES(4, '2014-03-01', 1);
INSERT INTO 주문상품 VALUES(4, '0003', 1);
INSERT INTO 주문상품 VALUES(4, '0004', 2);
```

- 여기서 `INSERT` 명령이 특정 원인으로 인해 에러가 발생한 경우를 가정해보자.
- 트랜잭션 기능을 사용하지 않을 때는 문제없이 실행된 `INSERT` 명령을 실행 전으로 되돌릴 수 없으므로 따로 `DELETE` 명령을 실행해 지워야한다.
- 즉, 위의 세 번째 `INSERT` 명령에서 에러가 발생했다고 치면, 앞서 실행한 두 개의 `INSERT` 명령에 의해 추가된 데이터를 `DELETE` 명령으로 삭제하는 처리가 필요하다.

---

## 2. 롤백과 커밋
- 이처럼 몇 단계로 처리를 나누어 SQL 명령을 실행하는 경우에 트랜잭션을 자주 사용한다.
- 트랜잭션을 사용해서 데이터를 추가한다면 에러가 발생해도 트랜잭션을 `롤백(rollback)`해서 종료할 수 있다.
- 롤백하면 트랜잭션 내에서 행해진 모든 변경사항을 잃었던 것으로 할 수 있다.
- 아무런 에러가 발생하지 않는다면 변경사항을 적용하고 트랜잭션을 종료하는데, 이때 `커밋(commit)`을 사용한다.

##### 트랜잭션을 롤백하면 변경한 내용이 적용되지 않는다!

### 자동커밋
- 트랜잭션을 사용해서 데이터를 추가할 때는 자동커밋을 꺼야 한다.
- `mysql` 클라이언트에서 명령을 실행할 때는 자동커밋이 켜져 있는 상태이다.
- `INSERT`나 `UPDATE`, `DELETE`가 처리될 때마다 트랜잭션은 암묵적으로 자동커밋 상태로 되어 있다.
- 자동커밋을 끄기 위해서는 명시적으로 트랜잭션의 시작을 선언할 필요가 있다.
- 트랜잭션을 시작할 때는 `START TRANSACTION` 명령을 사용한다.

**`트랜잭션 시작`**
```
START TRANSACTION
```

- 앞서 언급한 것처럼 트랜잭션을 종료하기 위해서는 변경된 내용을 적용한 후에 종료하는 '커밋'과 적용하지 않고 종료하는 '롤백'의 두 가지 방식이 있다.
- 커밋할 때에는 `COMMIT` 명령을 사용한다.

**`트랜잭션 내에서 실행한 명령을 적용한 후 종료`**
```
COMMIT
```

- 롤백은 `ROLLBACK` 명령을 사용한다.

**`트랜잭션 내에서 실행한 명령을 파기한 후 종료`**
```
ROLLBACK
```

- 트랜잭션 내에서 실행된 SQL 명령은 임시 데이터 영역에서 수행되다가, `COMMIT` 명령을 내리면 임시 데이터 영역에서 정식 데이터 영역으로 변경이 적용된다고 생각하면 된다.
- `ROLLBACK` 명령을 내리면 임시 데이터 영역에서의 처리는 버려진다.

![36강 트랜잭션의 커밋과 롤백](https://user-images.githubusercontent.com/68052095/102683893-6ae4e980-4217-11eb-9b5e-c96e6d8c3946.jpg)

다음 예제에서는 트랜잭션을 사용해 발주처리를 한다. 에러가 발생하지 않은 경우의 사례로, 트랜잭션은 `COMMIT`을 이용해 종료한다.

**`트랜잭션 내에서의 발주처리`**
```
START TRANSACTION;
INSERT INTO 주문 VALUES(4, '2014-03-01', 1);
INSERT INTO 주문상품 VALUES(4, '0003', 1);
INSERT INTO 주문상품 VALUES(4, '0004', 2);
COMMIT
```

- 이렇게 트랜잭션을 시작해서 SQL 명령을 실행하고 `COMMIT` 또는 `ROLLBACK` 명령으로 트랜잭션을 종료하는 일련의 처리방법을 '트랜잭션을 걸어서 실행한다' 또는 '트랜잭션 내에서 실행한다'라고 말한다.

##### 트랜잭션을 사용해서 처리하는 것으로 간단히 데이터를 관리할 수 있다!

---

## 3. 트랜잭션 사용법
- 발주처리와 같은 데이터 등록처리 과정에서는 대부분 트랜잭션 내에서 여러 개의 SQL 명령을 실행하게 된다.
- 다만 하나의 명령에 트랜잭션을 걸어 실행하는 것은 별로 의미가 없다.
- 트랜잭션 내에서 실행하는 복수의 SQL 명령은 세트 단위로 유효/무효가 된다.
- 다시 말하면, 반드시 세트로 실행하고 싶은 SQL 명령을 트랜잭션에서 하나로 묶어 실행한다는 것이다.
- 또 `ROLLBACK`은 에러가 발생한 경우 변경사항이 적용되지 않도록 하는 목적으로 주로 사용하지만, 에러가 발생하지 않아도 `ROLLBACK`을 하면 변경한 내용은 파기된다.
- 반대로 에러가 발생하더라도 `COMMIT`을 하면 문제없이 실행된 SQL 명령의 변경사항은 데이터베이스에 그대로 반영된다.

##### 세트로 실행하고 싶은 SQL 명령은 트랜잭션 내에서 실행한다!

- 트랜잭션을 시작할 때 사용하는 명령은 `START TRANSACTION`이라고 설명했지만 이것은 `MySQL`의 경우에 적용된다.
    - `MySQL`에서는 `START TRANSACTION` 외에도 `BEGIN`을 사용할 수 있다.
- `SQL Server`나 `PostgreSQL`에서는 `BEGIN TRANSACTION` 명령을 사용한다.
- `Oracle`이나 `DB2`에서 트랜잭션을 시작하는 명령은 따로 없다. 이 또한 표준화가 진행되지 못한 부분이다.
- 자동커밋은 클라이언트 툴의 기능이다.
- 미들웨어도 데이터베이스 접속 시 대개 자동커밋을 한다.
- 한편, 데이터베이스 서버에서는 언제나 트랜잭션을 걸 수 있는 상태로 SQL 명령이 실행된다.
- 트랜잭션을 사용할 경우에는 접속형태나 클라이언트 툴의 자동커밋 사용 여부 등, 트랜잭션 관련 기능을 파악해 둘 필요가 있다.
- `DELETE` 명령은 삭제 여부에 관해 사용자에게 확인하지 않는다고 설명했다.
- 불친절한 시스템이라고 생각할 수도 있으나, `DELETE` 명령을 트랜잭션 내에서 실행하는 경우에는 `ROLLBACK`으로 삭제를 취소할 수 있다.
- 단, 자동커밋으로 되어있는 경우에는 주의해야 한다. `ROLLBACK`으로 취소할 수 있는 것은 트랜잭션 내에서 실행했을 경우에 한해서이다.

---
