본문 바로가기
computing

20250519_DB8 트랜잭션, 동시성 제어

by greentworkshop 2025. 5. 19.

트랜잭션, 동시성 제어

 

 

트랜잭션의 ACID 성질

원자성(Atomicity) : 트랜잭션에 포함된 작업은 전부 수행되거나 아니면 전부 수행되지

않아야 (all or nothing) 함

일관성(Consistency) : 트랜잭션을 수행하기 전이나 수행한 후나 데이터베이스는 항상

일관된 상태를 유지해야 함

고립성(Isolation) : 수행 중인 트랜잭션에 다른 트랜잭션이 끼어들어 변경 중인 데이터

값을 훼손하는 일이 없어야 함

지속성(Durability) : 수행을 성공적으로 완료한 트랜잭션은 변경한 데이터를 영구히

저장해야 함


테이블 데이터 입력

CREATE DATABASE day_8;

USE day_8;
/*----------------------------------------customer 테이블-------------------------------------*/
CREATE TABLE customer(customer_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(10),
address VARCHAR(100), 
phone VARCHAR(15),
age INT
);

INSERT INTO customer(name, address, phone, age)
	VALUES ('손흥민', '영국 런던', '010-5001-0001', 30);
INSERT INTO customer(name, address, phone, age)
	VALUES ('유재석', '대한민국 서울', '010-6001-0001', 50);
INSERT INTO customer(name, address, phone, age)
	VALUES ('BTS 진', '대한민국 강원도', '010-7001-0001', 30);
INSERT INTO customer(name, address, phone, age)
	VALUES ('김하성', '미국 샌디에고', '010-8001-0001', 27);
INSERT INTO customer(name, address, age) 
VALUES ('김영진', '대한민국 서울', 25);
/*--------------------------------------products 테이블-----------------------------------*/
CREATE TABLE products(product_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
product VARCHAR(100),
brand VARCHAR(100),
price INT
);

INSERT INTO products(product, brand, price) VALUES ('양말', '아디다스', 7000);
INSERT INTO products(product, brand, price) VALUES ('긴바지', '무신사', 13000);
INSERT INTO products(product, brand, price) VALUES ('농구공', '나이키', 22000);
INSERT INTO products(product, brand, price) VALUES ('축구화', '나이키', 35000);
INSERT INTO products(product, brand, price) VALUES ('모자', '아디다스', 8000);
INSERT INTO products(product, brand, price) VALUES ('티셔츠', '아디다스', 6000);
INSERT INTO products(product, brand, price) VALUES ('와이셔츠', '스파오', 20000);
INSERT INTO products(product, brand, price) VALUES ('후드티', '스파오', 13000);
INSERT INTO products(product, brand, price) VALUES ('팬티', '캘빈클라인', 7500);
INSERT INTO products(product, brand, price) VALUES ('보온병', '노스페이스', 13000);
/*--------------------------------------orders 테이블------------------------------------*/
CREATE TABLE orders(order_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
customer_id INT,
product_id INT,
sale_price INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customer(customer_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);

INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (1, 1, 6000, '2023-03-01');
INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (1, 3, 21000, '2022-12-03');
INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (2, 5, 8000, '2022-12-03');
INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (3, 6, 6000, '2023-03-04');
INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (4, 7, 20000, '2023-03-05');
INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (1, 2, 12000, '2023-03-11');
INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (4, 8, 13000, '2023-02-26');
INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (3, 10, 12000, '2023-01-08');
INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (2, 10, 7000, '2023-03-09');
INSERT INTO orders(customer_id, product_id, sale_price, order_date) VALUES (3, 8, 13000, '2023-02-10');
/*----------------------------------------------------------------------------------*/

 

 

START TRANSACTION;
INSERT INTO products(product_id, product, brand, price)
	VALUES(99,'책1','동네서점',25000);
SELECT product 'example1'
	FROM products WHERE product_id = 99;
SAVEPOINT a;

UPDATE products SET product = '책2'WHERE product_id = 99;
SELECT product 'example2'
	FROM products WHERE product_id = 99;
SAVEPOINT b;

UPDATE products SET product = '책3' WHERE product_id = 99;
SELECT product 'example3'
	FROM products WHERE product_id = 99;

ROLLBACK TO b;
SELECT product 'example4'
	FROM products WHERE product_id = 99;


ROLLBACK TO a;
SELECT product 'example5'
	FROM products WHERE product_id = 99;
COMMIT;

 

🌱 1. 트랜잭션이란?

트랜잭션(Transaction) 은 데이터베이스에서 여러 작업을 하나의 묶음으로 처리하는 기능입니다.

  • 성공하면 COMMIT (변경사항 저장)
  • 문제가 생기면 ROLLBACK (변경 전으로 되돌림)
 
START TRANSACTION;

이건 "이제부터 내가 여러 작업을 묶어서 하나로 처리할게!" 라는 뜻이에요.


📥 2. INSERT - 데이터 추가하기

INSERT INTO products(product_id, product, brand, price) VALUES(99,'책1','동네서점',25000);
  • products 테이블에 새 상품 한 개를 추가해요.
  • product_id=99, 상품명은 '책1', 브랜드는 '동네서점', 가격은 25000원

🔍 3. SELECT - 데이터 확인하기

SELECT product 'example1' FROM products WHERE product_id = 99;
  • 방금 넣은 상품의 product 값이 무엇인지 확인해요.
  • 결과는 '책1' 이겠죠.

🎯 4. SAVEPOINT a;

SAVEPOINT a;
  • 'a'라는 이름의 저장 지점을 만들어요.
  • 여기까지의 상태(책1 상태)를 저장해 둬요.
  • 나중에 문제가 생기면 이 지점까지 되돌릴 수 있어요.

✏️ 5. UPDATE - 데이터 변경

UPDATE products SET product = '책2' WHERE product_id = 99;
  • 상품 이름을 '책2'로 바꿔요.
 
SELECT product 'example2' FROM products WHERE product_id = 99;
  • 결과는 '책2'

🎯 6. SAVEPOINT b;

SAVEPOINT b;
  • 또 다른 저장 지점(b)을 만들어요.
  • 현재 상태(책2 상태)를 저장해요.

✏️ 7. 또 한 번 업데이트

UPDATE products SET product = '책3' WHERE product_id = 99;
  • 상품명을 '책3'으로 바꿔요.
SELECT product 'example3' FROM products WHERE product_id = 99;
  • 결과는 '책3'

🔁 8. ROLLBACK TO b;

ROLLBACK TO b;
  • b 저장 지점으로 되돌려요.
  • 즉, 책3 → 책2로 돌아가요.
 
SELECT product 'example4' FROM products WHERE product_id = 99;
  • 결과는 '책2'

🔁 9. ROLLBACK TO a;

ROLLBACK TO a;
  • 이제는 a 지점으로 돌아가요.
  • 책2 → 책1로 돌아가요.
 
SELECT product 'example5' FROM products WHERE product_id = 99;
  • 결과는 '책1'

✅ 10. COMMIT;

COMMIT;
  • 이제까지의 변경 사항 중 **ROLLBACK TO a 이후 상태(책1)**를 최종 저장해요.
  • 이후에는 다시 돌이킬 수 없어요.

🎓 전체 흐름 정리

단계 상품 이름
처음 INSERT 책1
저장지점 a 책1
업데이트 1 책2
저장지점 b 책2
업데이트 2 책3
ROLLBACK TO b 책2
ROLLBACK TO a 책1
COMMIT 책1로 최종 저장
 

💡 이 코드를 통해 배우는 핵심

  1. 트랜잭션은 여러 데이터 변경을 묶어서 처리할 수 있다.
  2. SAVEPOINT는 중간 저장지점. 언제든지 그 지점으로 돌아갈 수 있다.
  3. ROLLBACK TO 저장지점은 그 시점으로 되돌린다.
  4. COMMIT을 하기 전까지는 실제로 DB에 저장되지 않는다.
  5. 실수를 막고, 안정적인 데이터 변경을 위해 이런 기능을 사용한다.

앤롤

공유락(LS, shared lock): 트랜잭션이 읽기를 할 때 사용하는 락
배타락(LX, exclusive lock): 읽고 쓰기를 할 때 사용하는 락

 

공유락과 배타락을 사용하는 규칙
데이터에 락이 걸려있지 않으면 트랜잭션은 데이터에 락을 걸 수 있다.
트랜잭션이 데이터 X를 읽기만 할 경우 LS(X)를 요청하고, 읽거나 쓰기를 할 경우 LX(X)를 요청한다.

 

다른 트랜잭션이 데이터에 LS(X)을 걸어둔 경우, LS(X)의 요청은 허용하고 LX(X)는 허용하지 않는다.
다른 트랜잭션이 데이터에 LX(X)을 걸어둔 경우, LS(X)와 LX(X) 모두 허용하지 않는다.
트랜잭션이 락을 허용받지 못하면 대기 상태가 된다.
밑은 허용 관계를 학 호환 행렬 (Compatibility Matrix)로 표시한 것이다.

 

데드락(dead lock), 무한 대기 상태에 빠질 수 있는 현상(교착상태)

두 개 이상의 트랜잭션이 각각 자신의 데이터에 대하여 락을 획득하고 상대방 데이터에 대해 락을 요청하면 무한 대기 상태에 빠질 수 있는 현상으로, 교착상태라고도 함
 

시나리오 설명:

•T1은 상품 번호가 1인 상품과 상품 번호가 2인 상품의 가격을 100원 올리고
•T2은 역순으로 상품 번호가 2인 상품과 상품 번호가 1인 상품의 가격을 10% 인상한다

문제 발생:

•T1은 product_id = 1인 상품에 락을 걸고, T2는 product_id = 2인 상품에 락을 건다
•T1이 product_id = 2인 상품에 락을 요청하면 대기 상태가 되고
•T2도 product_id = 1인 상품에 락을 요청하면 대기 상태가 되므로 데드락에 걸린다.

'computing' 카테고리의 다른 글

java 코드정리 - default  (0) 2025.06.12
20250522java11  (1) 2025.05.22
20250515java10  (0) 2025.05.15
20250508_java10  (0) 2025.05.08
나는 언제쯤 행복해질까?  (0) 2025.05.08