스프링 DB 1편 - 데이터 접근 핵심 원리 강의 | 김영한 - 인프런
김영한 | 백엔드 개발에 필요한 DB 데이터 접근 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 DB 접근 기술의 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니
www.inflearn.com
1. 트랜잭션 개념
- 트랜잭션을 이름 그대로 번역하면 거래라는 뜻이다.
- 즉, 데이터베이스에서 트랜잭션은 하나의 거래를 안전하게 처리하도록 보장해주는 것을 뜻한다.
- 데이터를 저장할 때 파일 저장이 아닌, 데이터베이스에 저장하는 이유 중 대표적인 이유는 트랜잭션을 지원하기 때문이다.
- 하나의 트랜잭션이 모두 성공해서 데이터베이스에 반영되는 것을 커밋이라하고, 작업 중 하나라도 실패해서 거래 이전으로 되돌리는 것을 롤백이라 한다.
2. 트랜잭션 원칙(ACID)
트랜잭션은 원자성(Atomicity), 일관성 (Consistency), 격리성(Isolation), 지속성(Durability)를 보장
- 원자성: 트랙잭션 내에서 실행한 작업들은 마치 하나의 작업인 것처럼 모두 성공하거나 실패해야 한다.
- 일관성: 모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 한다. 즉, 데이터베이스에서 정한 무결성 제약 조건을 항상 만족해야 한다.
- 격리성: 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리한다. 즉, 동시에 같은 데이터를 수정하지 못하도록 해야한다.
- 지속성: 트랜잭션을 성공적으로 끝내면 그 결과가 항상 기록되어야 한다. 중간에 시스템에 문제가 발생해도 데이터베이스 로그 등을 사용해서 성공한 트랜잭션 내용을 복구할 수 있어야 한다.
3. 데이터베이스 연결 구조와 DB 세션
- 클라이언트는 서버에 연결을 요청하고, 커넥션을 맺게 된다. 이 때 DB 서버는 내부에 세션이라는 것을 만든다.
- 앞으로 해당 커넥션을 통한 요청은 이 세션을 통해서 실행하게 된다. 즉, 연결된 세션이 SQL을 실행한다.
- 세션은 트랜잭션을 시작하고, 커밋 또는 롤백을 통해 트랜잭션을 종료한다.
- 커넥션 풀이 10개의 커넥션을 생성하면, 세션도 10개 만들어진다.
4. 자동 커밋, 수동 커밋
set autocommit false; //수동 커밋 모드 설정
insert into member(member_id, money) values ('data3',10000);
insert into member(member_id, money) values ('data4',10000);
commit; //수동 커밋
- 기존의 CRUD를 했을 때 별도의 커밋 없이 조회가 되는 이유는 기본적으로 autoCommit 기능이 활성화 되어 있기 때문
- 다음과 같이 해당 기능을 비활성화 해두면 커밋되지 않는다. 단, 이후에 꼭 commit 또는 rollback을 호출해야 한다.
- 수동 커밋 모드나, 자동 커밋 모드는 한번 설정하면 해당 세션에서는 계속 유지된다. 중간에 변경은 가능하다.
5. 트랜잭션 동작 원리
[트랜잭션 사용법]
- 데이터 변경 쿼리를 실행하고 데이터베이스에 그 결과를 반영하려면 commit을 호출
- 데이터베이스에 그 결과를 반영하고 싶지 않으면 rollback을 호출
- 데이터베이스에 결과를 반영하는 commit, rollback이 호출되기 전까지는 해당 트랜잭션을 관리하는 세션에서 임시로 데이터를 저장한다.
- 이 후 커밋을 하면 다른 세션에서도 조회가 가능하다.
6. 트랜잭션 계좌이체 예제
- memberA: 10000원 보유
- memberB: 10000원 보유
- 만약 계좌이체를 실행하는 도중에 memberB에 대한 SQL에 오류가 발생한다면 memberA의 돈은 줄어들지만, memberB의 돈을 증가시키는 것에는 실패하여 문제가 발생
- 이러한 문제가 발생했을 때, 강제로 커밋을 호출하면 안된다.
- 이럴 때는 롤백을 호출해서 트랜잭션을 시작하기 전 단계로 데이터를 복구해야 한다.
7. DB 락(DB LOCK)
- 트랜잭션 작업에서 문제가 발생하는 요인 중 하나는 세션 A에서 커밋을 수행하지 않았는데 세션 B에서 동시에 같은 데이터를 수정하게 되는 경우이다. 해당 경우에 원자성이 위반 된다.
- 이러한 문제를 방지하려면, 세션이 트랜잭션을 시작하고 데이터를 수정하는 동안 (커밋 또는 롤백 전까지) 다른 세션에서 해당 데이터를 수정할 수 없게 막아야한다. 이 것을 락(Lock) 이라한다.
1. 세션1은 트랜잭션을 시작
2. 세션1은 memberA의 money 를 500으로 변경을 시도. 이때 세션1이 세션2보다 조금이라도 더 빨리 요청한다면 세션1은 락을 획득한다.
3. 세션1은 락을 획득했으므로 해당 로우에 update sql을 실행
4. 세션2는 트랜잭션을 시작세션2도 memberA의 money를 변경하려고 시도.
5. 이때 락을 이미 세션1이 가지고 있으므로 락이 돌아올 때 까지 대기한다
6. 참고로 락 대기 시간을 넘어가면 락 타임아웃 오류가 발생. 락 대기 시간은 설정 가능
7. 세션1은 commit 을 수행하고 커밋으로 트랜잭션이 종료되었으므로 락도 반납한다.
8. 락을 갖기위해 대기하던 세션2가 락을 획득
9. 세션2는 update sql을 수행
결론
- 트랜잭션을 통해 롤백을 수행해서 모든 데이터를 정상적으로 초기화 할 수 있게 되었다.
- 그러나 애플리케이션에서 DB 트랜잭션을 적용하려면 서비스 계층이 매우 지저분해진다. 스프링에서 이 문제를 @Transactional 을 지원해서 해결해준다.
'DB' 카테고리의 다른 글
[DB] Postgresql 14 간단 설치 및 DBeaver에서 데이터베이스 생성(macOS) (0) | 2025.04.01 |
---|---|
[DB] 트랜잭션(Transaction)매니저 & 프록시 & 트랜잭션 AOP (0) | 2024.08.11 |
[DB] 관계형 데이터베이스(RDBMS) 개념 용어 정리 (0) | 2024.07.29 |
[DB] 데이터베이스 기본개념 용어 정리 (0) | 2024.07.29 |
[DB] Connection Pool 과 DataSource (2) | 2024.07.23 |