트랜잭션 - 개념 이해
모든 작업이 성공해서 데이터베이스에 정상 반영하는 것을 커밋(Commit)이라 하고, 작업중 하나라도 실패해서 거래 이전으로 되돌리는 것을 롤백(Rollback)이라 한다.
트랜잭션 ACID
- 원자성(Atomicity): All or Nothing
- 일관성(Consistency): 모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 한다. 예를 들어 데이터베이스에서 정한 무결성 제약 조건을 항상 만족해야 한다.
- 격리성(Isolation): 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 경리한다. 격리성은 동시성과 관련된 성능 이슈로 인해 트랜잭션 격리 수준(Isolation level)을 선택할 수 있다.
- 지속성(Durability): 트랜잭션은 성공적으로 끝내면 그 결과가 항상 기록되어야 한다.
트랜잭션은 원자성, 일관성, 지속성을 보장한다. 문제는 격리성인데 트랜잭션 간에 격리성을 완벽히 보장하려면 트랜잭션을 거의 순서대로 실행해야 한다. 이렇게 하면 동시 처리 성능이 매우 나빠진다. 이런 문제로 ANSI 표준은 트랜잭션 격리 수준을 4단계로 나누어 정의했다.
트랜잭션 격리 수준 - Isolation level
- READ UNCOMMITED(커밋되지 않는 읽기)
- READ COMMITED(커밋된 읽기) - 일반적
- REPEATABLE READ(반복 가능한 읽기)
- SERIALIZABLE(직렬화 가능)
데이터베이스 연결 구조와 DB 세션
- 사용자는 웹 애플리케이션 서버(WAS)나 DB 접근 툴 같은 클라이언트를 사용해서 데이터베이스 서버에 접근할 수 있다. 클라이언트는 데이터베이스 서버에 연결을 요청하고 커넥션을 맺게 된다. 이 때 데이터베이스 서버는 내부에 세션이라는 것을 만든다. 그리고 앞으로 해당 커넥션을 통한 모든 요청은 이 세션을 통해서 실행하게 된다.
- 쉽게 이야기해서 개발자가 클라이언트를 통해 SQL을 전달하면 현재 커넥션에 연결된 세션이 SQL을 실행한다.
- 세션은 트랜잭션을 시작하고, 커밋 또는 롤백을 통해 트랜잭션을 종료한다. 그리고 이후에 새로운 트랜잭션을 다시 시작할 수 있다.
- 사용자가 커넥션을 닫거나, 또는 DBA(DB 관리자)가 세션을 강제로 종료하면 세션은 종료된다.
- 커넥션 풀이 10개의 커넥션을 생성하면, 세션도 10개 만들어진다.
트랜잭션 - DB 예제1 - 개념 이해
트랜잭션 사용법
- 데이터 변경 쿼리를 실행하고 데이터베이스에 그 결과를 반영하려면 Commit을 호출하고, 결과를 반영하고 싶지 않으면 Rollback을 호출하면 된다.
- Commit을 호출하기 전까지는 임시로 데이터를 저장하는 것이다. 따라서 해당 세션에게만 변경 데이터가 보이고 다른 세션에게는 변경 데이터가 보이지 않는다.
- 커밋하지 않는 데이터를 다른곳에서 조회하면 데이터 정합성에 문제가 발생한다.
트랜잭션 - DB 예제2 - 자동 커밋, 수동 커밋
자동 커밋 설정
set autocommit true;
insert into member(member_id, money) values ('data1', 1000);
insert into member(member_id, money) values ('data2', 1000);
수동 커밋 설정
set autocommit false;
insert into member(member_id, money) values ('data1', 1000);
insert into member(member_id, money) values ('data2', 1000);
commit;
- 보통 자동 커밋 모드가 기본으로 설정된 경우가 많기 때문에, 수동 커밋 모드로 설정하는 것을 트랜잭션 시작한다고 표현할 수 있다.
- 수동 커밋 모드나 자동 커밋 모드는 한번 설정하면 해당 세션에서 계속 유지되며, 중간에 변경하는 것도 가능하다.
트랜잭션 - DB 예제3 - 트랜잭션 실습
트랜잭션 - DB 예제4 - 계좌이체
DB 락 - 개념 이해
DB 락 - 변경
락 타임아웃
SET LOCK_TIMEOUT <millisecondes>: 락 타임아웃 시간을 설정한다. 해당 시간동안 락을 얻지 못하면 락 타임아웃 오류가 발생한다.
DB 락 - 조회
일반적인 조회는 락을 사용하지 않는다.
조회와 락
- 데이터를 조회할 때도 락을 획득하고 싶을 때가 있다. 이럴 때는 select for update 구문을 사용하면 된다.
- 이렇게 하면 세션1이 조회 시점에 락을 가져가버리기 때문에 다른 세션에서 해당 데이터를 변경할 수 없다.
조회 시점에 락이 필요한 경우는 언제일까?
- 예를 들어서 애플리케이션 로직에서 memberA의 금액을 조회한 다음에 이 금액 정보로 애플리케이션에서 어떤 계산을 수행한다. 그런데 이 계산이 돈과 관련된 매우 중요한 계산이어서 계산을 완료할 때까지 memberA의 금액을 다른 곳에서 변경하면 안된다. 이럴 때 조회 시점에 락을 획득하면 된다.
set autocommit false;
select * from member where member_id='memberA' for update;
트랜잭션 - 적용1
트랜잭션 - 적용2
주의
- 커넥션 유지가 필요한 두 메서드는 파라미터로 넘어온 커넥션을 사용해야 한다. 따라서 con = getConnection() 코드가 있으면 안된다.
- 커넥션 유지가 필요한 두 메서드는 리포지토리에서 커넥션을 닫으면 안된다. 커넥션을 전달 받은 리포지토리 뿐만 아니라 이후에도 커넥션을 계속 이어서 사용하기 떄문이다. 이후 서비스 로직이 끝날 때 트랜잭션을 종료하고 닫아야 한다.
정리
출처 - 김영한의 스프링 DB 1편
'Backend > Java' 카테고리의 다른 글
자바 고급 1편 - 스레드 생성과 실행 (0) | 2024.11.05 |
---|---|
자바 고급 1편 - 프로세스와 스레드 소개 (4) | 2024.10.31 |
커넥션풀과 데이터소스 이해 (0) | 2024.08.27 |
컬렉션 프레임워크 - 순회, 정렬, 전체 정리 (0) | 2024.08.21 |
컬렉션 프레임워크 - Map, Stack, Queue (0) | 2024.08.21 |