트랜잭션
- 데이터를 저장할 때 단순히 파일이 아닌 DB에 저장하는 이유는?
- DB가 트랜잭션을 지원해주기 때문에
- 트랜잭션 : DB에서 하나의 거래를 안전하게 처리하도록 보장해주는 것으로 DB에서 일어나는 논리적인 작업 단위
- 여러 작업(쿼리)을 하나의 작업처럼 묶어서 동작해야 한다.
- 커밋 (Commit) : 모든 작업이 성공해서 DB에 정상 반영하는 것
- 롤백 (Rollback) : 작업 중 하나라도 실패해서 작업 이전으로 되돌리는 것
- 트랜잭션이 커밋되거나 롤백되면 해당 트랜잭션은 종료된다.
- 트랜잭션은 커넥션 내에서 관리되며 특정 커넥션에 종속적이다.
- 커넥션이 열려있어야 트랜잭션을 시작하거나 완료할 수 있다.
트랜잭션 ACID
- 트랜잭션은 ACID를 보장해야 한다.
- 트랜잭션 ACID
- 원자성 (Atomicity) : 트랜잭션 내에서 실행한 작업들은 마치 하나의 작업인 것처럼 모두 성공하거나 모두 실패해야 한다.
- 일관성 (Consistency) : 모든 트랜잭션은 일관성 있는 DB 상태를 유지해야 한다.
- DB에서 정한 무결성 제약 조건을 항상 만족해야 한다.
- 격리성 (Isolation) : 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리한다.
- 동시에 같은 데이터를 수정하지 못하도록 해야한다.
- 동시성과 관련된 성능 이슈로 인해 트랜잭션 격리 수준을 선택할 수 있다.
- 지속성 (Durability) : 트랜잭션을 성공적으로 끝내면 그 결과가 항상 기록되어야 한다.
- 중간에 시스템에 문제가 발생하더라도 DB 로그 등을 사용해서 성공한 트랜잭션 내용을 복구해야 한다.
- 트랜잭션은 원자성, 일관성, 지속성을 보장한다.
- 격리성은 완벽히 보장하려면 순서대로 실행해야하는데 동시 처리 성능이 매우 나빠진다.
=> 이런 문제로 인해 트랜잭션 격리 수준을 4단계로 정의
- 격리성은 완벽히 보장하려면 순서대로 실행해야하는데 동시 처리 성능이 매우 나빠진다.
- 트랜잭션 격리 수준 - Isolation level
- READ UNCOMMITED (커밋되지 않은 읽기)
- READ COMMITTED (커밋된 읽기)
- REPEATABLE READ (반복 가능한 읽기)
- SERIALIZABLE (직렬화 가능)
- 단계가 낮아질수록 성능이 느려지며 일반적으로 READ COMMITTED 사용한다.
DB 연결 구조와 DB 세션
- 사용자는 WAS나 DB 접근 툴같은 클라이언트를 사용해 DB 서버에 접근할 수 있다.
- 클라이언트는 DB 서버에 연결 요청, 커넥션을 맺는다.
- DB 서버는 내부에 세션을 생성한다.
- 세션이 생성되면 해당 커넥션을 통한 모든 요청은 해당 세션을 통해서만 실행되게 된다.
- 개발자가 클라이언트를 통해 SQL을 전달하면 커넥션에 연결된 세션이 SQL을 실행한다.
- 세션은 트랜잭션을 시작하고 커밋 / 롤백을 통해 트랜잭션을 종료한다. (이후 다시 시작 가능)
- 사용자가 커넥션을 닫거나 DBA (DB 관리자)가 세션을 강제로 종료하면 세션은 종료된다.
트랜잭션 - DB
- 트랜잭션 사용법
- 데이터 변경 쿼리를 실행하고 DB에 그 결과를 반영하려면 commit을 호출, 결과를 반영하고 싶지 않으면 roolback을 호출한다.
- 커밋을 호출하기 전까지는 임시로 데이터를 저장한다.
- 롤백을 호출하면 트랜잭션을 시작하기 직전의 상태로 복구된다.
- 트랜잭션을 시작한 세션(사용자)에게만 변경 데이터가 보이고 다른 세션(사용자)에게는 변경 데이터가 보이지 않는다.
- 등록, 수정, 삭제 모두 같은 원리이다.
- 데이터 변경 쿼리를 실행하고 DB에 그 결과를 반영하려면 commit을 호출, 결과를 반영하고 싶지 않으면 roolback을 호출한다.
//자동 커밋 예시
set autocommit true; //자동 커밋 모드 설정
insert into member(member_id, money) values ('data1',10000); //자동 커밋
insert into member(member_id, money) values ('data2',10000); //자동 커밋
//수동 커밋 예시
set autocommit false; //수동 커밋 모드 설정
insert into member(member_id, money) values ('data3',10000);
insert into member(member_id, money) values ('data4',10000);
commit; //수동 커밋
- 자동 커밋 vs 수동 커밋
- 자동 커밋으로 설정 시 각각의 쿼리 실행 직후에 자동으로 커밋을 호출한다.
- 커밋이나 롤백을 직접 호출하지 않아도 되지만 트랜잭션 기능을 재대로 사용할 수 없다.
- 일반적으로 자동 커밋이 기본 값이다.
- 수동 커밋 모드로 설정하는 것을 트랜잭션을 시작하는 것으로 볼 수 있다.
- 수동 커밋 설정 시 commit, rollback을 반드시 호출해줘야 한다.
- commit, rollback을 호출하지 않는 경우 DB에 지정된 TimeOut 시간을 넘어가면 자동 rollback이 된다.
- 커밋 모드 설정 시 해당 세션에서 계속 유지되며 중간에 변경할 수 있다.
- 자동 커밋으로 설정 시 각각의 쿼리 실행 직후에 자동으로 커밋을 호출한다.
- 트랜잭션은 비지니스 로직이 있는 서비스 계층에서 시작해야 한다.
- 비지니스 로직이 잘못되면 해당 비지니스 로직으로 인해 문제가 되는 부분을 함께 롤백해야 하기 때문
- 트랜잭션을 시작하기 위해서는 커넥션이 필요하기에 서비스 계층에서 커넥션을 만들고 트랜잭션 커밋 이후 커넥션을 종료해야 한다.
- 애플리케이션에서 DB 트랜잭션을 사용하려면 트랜잭션을 사용하는 동안 같은 커넥션을 유지해야 한다.
- 애플리케이션에서 같은 커넥션을 유지하려면?
- 가장 단순한 방법은 커넥션을 파라미터로 전달해서 사용하는 것
- 이 경우 커넥션을 계속 유지해서 같은 커넥션을 사용해야 하므로 레포지토리 내에서 close()를 하면 안된다.
- 서비스 로직이 끝날 때 트랜잭션을 종료하고 close()해줘야 한다.
- 커넥션 풀을 사용하는 경우 con.close()하기 전에 con.setAutoCommit(false)로 트랜잭션을 시작했다면 con.setAutoCommit(true)로 기본 값인 자동 커밋상태로 복구해주는 것이 좋다.
- 이 방법은 코드가 매우 복잡해진다.
- 이 경우 커넥션을 계속 유지해서 같은 커넥션을 사용해야 하므로 레포지토리 내에서 close()를 하면 안된다.
- 가장 단순한 방법은 커넥션을 파라미터로 전달해서 사용하는 것
DB 락
- 세션이 트랜잭션을 시작하고 데이터를 수정하는 동안 커밋이나 롤백 전까지 다른 세션에서 해당 데이터를 수정할 수 없게 막아야 한다.
- 이러한 문제를 해결하기 위해서 락을 제공한다.
- 세션 1, 2가 memberA에 접근하는 경우
- 세션 1이 2보다 빨리 접근했기에 세션 1이 트랜잭션을 시작
- 먼저 락을 획득하고 Update 쿼리 수행
- 세션 2도 트랜잭션을 시작
- 락을 획득해야하지만 세션 1이 락을 가지고 있기에 락이 돌아올 때 까지 대기
- 세션 1이 커밋을 수행하면 트랜잭션이 종료되며 락을 반납
- 대기하던 세션 2가 락을 획득하고 Update 쿼리 수행
- 세션 2가 커밋을 수행하고 트랜잭션이 종료되며 락을 반납
- 락 타임아웃 : 락을 얻기위해 대기하는 시간인 락 타임아웃 시간을 설정할 수 있으며 시간을 넘어가는 경우 타임아웃 오류가 발생한다.
DB 락 - 조회
- 일반적인 조회는 락을 사용하지 않는다.
- 데이터를 조회할 때도 락을 획득하고 싶은 경우 select for update 구문 사용
- 조회와 동시에 선택한 row의 락을 획득할 수 있다.
- 조회 시점에 락이 필요한 경우는?
- 트랜잭션 종료 시점까지 해당 데이터를 다른 곳에서 변경하지 못하도록 강제로 막아야할 때 사용한다.
- 다른 세션에서 데이터를 변경하려면 락이 필요하기에 획득할 때까지 대기하게 된다.
- 조회도 마찬가지로 커밋하기 전까지는 락을 반납하지 않는다.
- 트랜잭션 종료 시점까지 해당 데이터를 다른 곳에서 변경하지 못하도록 강제로 막아야할 때 사용한다.
정리
- 트랜잭션 : DB에서 일어나는 논리적인 작업 단위
- 커밋 : 모든 작업이 성공해서 DB에 정상적으로 반영하는 것
- 커밋을 호출하기 전까지는 데이터가 임시로 저장된다.
- 롤백 : 작업 중 하나라도 실패해서 작업을 트랜잭션 시작 직전으로 되돌리는 것
- 트랜잭션이 커밋되거나 롤백되면 해당 트랜잭션은 종료된다.
- 트랜잭션은 커넥션 내에서 관리되며 특정 커넥션에 종속적이다.
- 커넥션이 열려있어야 트랜잭션을 시작하거나 완료할 수 있다.
- 커밋 : 모든 작업이 성공해서 DB에 정상적으로 반영하는 것
- 서버와 클라이언트간 커넥션이 맺어지면 세션이 생성되고 해당 세션을 통해서 모든 요청이 수행된다.
- 일반적으로 자동 커밋 상태가 기본 값이며 수동 커밋으로 변경하는 것을 트랜잭션 시작이라고 한다.
- 트랜잭션은 비지니스 로직이 있는 서비스 계층에서 시작해야 한다.
- 세션이 트랜잭션을 시작하고 데이터를 수정하는 동안 커밋이나 롤백 전까지 다른 세션에서 해당 데이터를 수정할 수 없도록 제공하는 락을 사용한다.
- 일반적인 조회는 락을 사용하지 않지만 select for update 구문을 사용하면 데이터 조회 시 락을 획득할 수 있다.
출처 : [인프런 김영한 스프링 DB 1편 - 데이터 접근 핵심 원리]
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1/dashboard
스프링 DB 1편 - 데이터 접근 핵심 원리 강의 | 김영한 - 인프런
김영한 | 백엔드 개발에 필요한 DB 데이터 접근 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 DB 접근 기술의 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니
www.inflearn.com
'Spring > [인프런 김영한 스프링 DB 1편 - 데이터 접근 핵심 원리]' 카테고리의 다른 글
[인프런 김영한 스프링 DB 1편 - 데이터 접근 핵심 원리] 스프링과 문제 해결 - 예외 처리, 반복 (0) | 2024.11.19 |
---|---|
[인프런 김영한 스프링 DB 1편 - 데이터 접근 핵심 원리] 자바 예외 이해 (2) | 2024.11.18 |
[인프런 김영한 스프링 DB 1편 - 데이터 접근 핵심 원리] 스프링과 문제 해결 - 트랜잭션 (2) | 2024.11.17 |
[인프런 김영한 스프링 DB 1편 - 데이터 접근 핵심 원리] 커넥션풀과 데이터소스 이해 (0) | 2024.11.14 |
[인프런 김영한 스프링 DB 1편 - 데이터 접근 핵심 원리] JDBC 이해 (0) | 2024.11.11 |