| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 정규화
- CTE
- index
- 탄력적 ip
- sub-query
- ASW
- 정보처리기사
- SQL
- DDL
- springboot
- 정처기
- SubQuery
- NoSQL
- Transaction
- SQLite
- databse
- MySQL
- PostgreSQL
- db
- dml
- mongoDB
- 보안 그룹
- VPC
- database
- redis
- DevOps
- Join
- aws
- EC2
- Github Actions
- Today
- Total
sellen
Transaction 본문

💡 이 내용 이후로 모든 SQL 관련 내용은 NomadCoder 강의를 듣고 정리한 글입니다.
아래의 링크에 SQL 학습에 필요한 데이터가 존재합니다.
https://nomadcoders.co/sql-masterclass
아래의 글과 함께 보시면 좋습니다.
Transaction
DB에서 사용되는 연산의 최소 단위
하나의 transaction 내에서 에러가 발생하면 모든 연산은 취소되어야 한다.
SELECT와 같은 명령어도 1개의 transaction이다
Transaction이 왜 필요한가?
아래처럼 은행 계좌 DB가 있다고 가정하자.
CREATE TABLE accounts (
account_id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
account_holder VARCHAR(100) NOT NULL,
balance DECIMAL(10,2) NOT NULL CHECK ( balance >= 0 )
);
INSERT INTO accounts (account_holder, balance)
VALUES
('nico', 1000.00),
('lynn', 2000.00);
nico가 lynn에게 500원을 송금하려면 아래처럼 연산이 이뤄져야 하지만
UPDATE accounts SET balance = balance - 500 WHERE account_holder = 'nico';
UPDATE accounts SET balance = balance + 500 WHERE account_holder = 'lynn';
UPDATE accounts SET balance = balance + 500 WHERE account_holder = 'lynn';
이 코드가 실행되기 전 DB에 문제가 생겨 실행이 안되면 nico의 돈만 줄어들고 lynn은 돈을 받지 못한다.
Transaction 설정
- PostgreSQL에서는 BEGIN ~ COMMIT으로 감싸주면 된다.
- MySQL에서는 START TRANSACTION ~ COMMIT으로 감싸주면 된다.
BEGIN;
UPDATE accounts SET balance = balance - 1500 WHERE account_holder = 'nico';
UPDATE accounts SET balance = balance + 1500 WHERE account_holder = 'lynn';
COMMIT;
위 SQL문에서 nico의 잔금은 1000원 이므로 -1500 하면 CHECK ( balance >= 0 )에 의해 막힌다.
그러면 Transaction에 의해 연산이 취소되고 실행 전 상태로 롤백된다.
Transaction의 특징
ACID
| 구분 | 설명 |
| Atomic | 모든 작업이 성공하거나, 그렇게 될 수 없을 경우 전부 실행되서는 안된다. |
| Consistent | 실행 전 상태와 실행 후 상태가 항상 constraint, cascade 같은 조건을 충족해야 한다. |
| Isolated | transaction이 commit 되기 전까지는 다른 transation에선 확인이 불가능하다. |
| Durable | Transaction이 commit이 되면 DB를 재시작해도 변경 사항이 그대로 유지되어야 한다. |
Save Point
transaction 작업을 수행하다 실패하면 완전 롤백되지 않고 save point까지 롤백된다.
BEGIN; -- MySQL -> start transaction
UPDATE accounts SET balance = balance + 1000 WHERE account_holder = 'nico';
SAVEPOINT step_one;
UPDATE accounts SET account_holder = 'Lynn' WHERE account_holder = 'lynn';
UPDATE accounts SET balance = balance - 1000 WHERE account_holder = 'lynn';
ROLLBACK TO SAVEPOINT step_one;
COMMIT;
ROLLBACK TO SAVEPOINT step_one; 에 의해 lynn → Lynn과 Lynn의 잔금이 -1000 이 된 부분만 롤백된다.
Isolation Level
transaction 현상을 막기 위한 방법
💡 PostgreSQL의 기본 설정은 Read Uncommited MySQL의 기본 설정은 Repeatable read이다.
transaction 현상
| 구분 | 설명 |
| Dirty Read |
|
| Nonrepeatable Read |
|
| Phantom Read |
|
| Serialization Anomaly |
|
Isolation Level 종류
| Isolation Level | Dirty Read | Nonrepeatable Read | Read Phantom | Serialization Anomaly |
| Read uncommitted | 허가 PostgreSQL에서는 불가 |
가능 | 가능 | 가능 |
| Read committed | 불가능 | 가능 | 가능 | 가능 |
| Repeatable read | 불가능 | 불가능 | 허가 PostgreSQL에서는 불가 |
가능 |
| Serializable | 불가능 | 불가능 | 불가능 | 불가능 |
- Read uncommitted
- 아직 commit 되지 않은 데이터를 다른 transaction에서 볼 수 있다.
- Read committed
- 아직 commit 되지 않은 데이터를 다른 transaction에서 볼 수 없다.
- PostgreSQL에서는 Read uncommitted와 Read committed 두 레벨이 같다.
- Repeatable read
- A에서 데이터를 변경하고 아직 commit을 하지 않은 상태일 때, B(Repeatable read 모드)에서는 변경 전 데이터를 읽는다.
- 하지만 A가 commit이 된 후라도 B는 해당 transaction을 닫지 않는 한 계속 이전 데이터를 읽는다.
- 이때, transaction이 시작할 때 데이터를 읽는 것이 아닌 쿼리가 실행될 때 데이터를 읽는다
- B가 transaction 열림 (BEGIN) → A 작업 완료 (commit) → B 쿼리 실행
- 이 순서일 경우 B에서는 A에서 작업 완료 후의 데이터를 읽게 된다.
BEGIN SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT * FROM accounts; -- 이 쿼리가 실행된 시점의 데이터로 고정된다. COMMIT;
Isolation Level 변경
- MySQl
- SET SESSION TRANSACTION ISOLATION LEVEL {isolation_level};
- session 설정 변경이므로 이후 모든 transaction에 적용된다.
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION; -- COMMIT; - PostgreSQL
- SET TRANSACTION ISOLATION LEVEL {isolation_level};
- transaction 내부에 작성하므로 해당 transaction만 적용된다.
BEGIN; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- COMMIT;
Locks
| 상황 | 설명 |
| Read Committed 일 때 |
|
| Repeatable Read 일 때 |
|
Lock Share
SELECT FOR UPDATE
그 어떤 transaction도 해당 row의 lock을 걸 수 없으며 데이터 변경도 하지 못한다.
BEGIN;
SELECT balance
FROM accounts
WHERE account_holder = 'lynn'
FOR UPDATE; -- exclusive lock
COMMIT;
BEGIN;
SELECT * FROM accounts;
UPDATE accounts SET account_holder = 'Lynn' WHERE account_holder = 'lynn';
COMMIT;
2 종류의 transaction이 있을 때 첫 번째 쿼리의 FOR UPDATE에 의해 데이터가 update가 되지 않음에도 두 번째 transaction은 첫 번째 transaction 작업이 완료될 때까지 대기해야 한다.
SELECT FOR UPDATE를 사용하면 다른 transaction은 해당 row에 lock조차 걸 수 없다.
SELECT FOR SHARE
그 어떤 transaction도 해당 row의 데이터 변경은 할 수 없으나 lock은 걸 수 있다.
BEGIN;
SELECT balance
FROM accounts
WHERE account_holder = 'lynn'
FOR SHARE; -- shared lock
COMMIT;
BEGIN;
SELECT * FROM accounts;
UPDATE accounts SET account_holder = 'Lynn' WHERE account_holder = 'lynn';
COMMIT;
SELECT FOR UPDATE와 같은 현상이 발생한다.
하지만 SELECT FOR UPDATE와는 다르게 여러 transaction이 같은 row에 lock을 걸 수 있다.
만약 다른 transaction이 해당 row를 변경하고자 하면 기존의 transaction들의 작업을 모두 완료해야 한다.
'DataBase > 관계형 DB' 카테고리의 다른 글
| SQL에서 JSON 다루기 (4) | 2025.07.21 |
|---|---|
| DCL (0) | 2025.07.21 |
| Function & Procedures (5) | 2025.07.21 |
| 정규화 - PostgreSQL (1) | 2025.07.20 |
| PostgreSQL에서의 ALTER문 (1) | 2025.07.20 |