Spring Boot 의 트랜잭션 : @Transactional
3탄에서는 스트링부트에서의 트랜잭션에 대해 알아보려고 한다.
@Transactional 이란?
Spring Boot에서 @Transactional은 트랜잭션 처리를 하기 위해 사용된다.
메소드 또는 클래스 레벨에서 사용할 수 있으며,
메소드 또는 클래스 내에서 실행되는 모든 데이터베이스 작업이 하나의 트랜잭션 묶여서 처리가 되며,
트랜잭션이 적용된 메소드 또는 클래스에서
작업 실행 중 예외가 발생하면
자동으로 롤백(Rollback)하여 이전 상태로 되돌려준다.
1. 트랜잭션 시작
2. 데이터베이스 연결
3. 요청 실행
4. 예외 발생 여부 확인
5-1. 성공적으로 실행되면 변경 내용을 영구적으로 저장하고, 트랜잭션 종료 커밋(Commit)
5-2. 에외 발생하면 변경 내용을 롤백하고, 트랜잭션 종료 롤백(Rollback)
트랜잭션 경계 설정
트랜잭션 경계는
트랜잭션의 시작과 종료 지점을 의미한다.
@Transactional 어노테이션을 사용하여 메서드나 클래스에 경계를 설정하면,
해당 영역에서 자동으로 트랜잭션을 시작하고 종료할 수 있다.
예를들어,
메소드에 @Transactional을 적용하면, 해당 메소드가 트랜잭션 경계 내에서 실행된다.
메소드 시작 시 트랜잭션을 시작하고, 메소드내 작업 완료 시 커밋 또는 롤백을 수행한다.
속성 설정
@Transactional의 속성을 사용하여
트랜잭션 동작을 세부적으로 제어할 수 있다.
1. readOnly
- 트랜잭션의 읽기 전용 여부 설정
- 데이터 수정 작업 없이 조회 작업만 수행하는 경우 사용하여 성능을 향상시킬수 있다.
- 기본값 : false
- readOnly를 true로 설정하면 트랜잭션이 읽기 전용으로 간주된다.
해당 트랜잭션 내에서 데이터를 수정하는 작업이 없음을 나타낸다.
- @Transactional(readOnly = true)
2. isolation
- 트랜잭션의 격리 레벨을 설정
- 격리 레벨은 동시에 여러 트랜잭션이 실행될 때 트랜잭션 간의 데이터 접근을 제어하는 데 사용된다.
- 기본값 : DEFAULT
- 여러개의 트랜잭션이 발생하는 경우,
생길 수 있는 동시성 문제를 해결 할 수 있는 isolation속성에는
다음과 같은 값을 설정할 수 있다.
1. DEFAULT
- 기본 격리 레벨
- DBMS의 isolation Level을 따른다. ( MySQL의 격리레벨은 REPEATABLE_READ이다.)
2. READ_UNCOMMITTED (커밋되지 않는 읽기, level 0)
- 트랜잭션 처리중이거나 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용.
- 동시성 부작용 Dirty Read 발생 → 다른 트랜잭션에서 처리하는 작업이 완료되지 않았는데도 다른 트랜잭션에서 읽을 수 있는 현상
3. READ_COMMITTED (커밋된 읽기, level 1)
- 트랜잭션에서 커밋된 데이터만 읽는 것을 허용.
- Dirty Read 방지
- A라는 데이터가 B로 변경되는 동안 다른 사용자는 해당 데이터에 접근할 수 없다.
4. REPEATABLE_READ (반복 가능한 읽기, level 2)
- 읽은 데이터를 다시 읽을 때 같은 값이 나오는 것을 보장한다.
- 트랜잭션이 완료될 때까지 SELECT문을 사용하는 모든 데이터에 Shared Lock 처리한다. 따라서, 다른 사용자는 해당 영역에 대한 데이터 수정이 불가능하다.
- 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지, 후행 트랜잭션이 갱신하거나 삭제가 불가능 하기 때문에 같은 데이터를 두 번 쿼리했을 때 일관성 있는 결과를 리턴한다.
5. SERIALIZABLE (직렬화 가능, level 3)
- 동시에 실행 중인 다른 트랜잭션에서 접근하지 못하도록 하며, 완벽한 읽기 일관성 모드 제공한다.
- 동시성 부작용을 모두 방지한다. 동시 호출을 순차적으로 실행하도록 제한하는 설정이므로, 성능 저하의 우려가 있다.
트랜잭션이 완료될 때까지 SELECT문을 사용하는 모든 데이터에 Shared Lock이 걸리므로 다른 사용자는 그 영역에 해당하는 데이터에 대한 수정 및 입력이 불가능하다.
- 적절한 격리 수준은 동시성과 데이터 일관성 사이의 균형을 유지하기 위해 선택되어야 한다. 필요에 따라 격리 수준을 설정하여 트랜잭션의 동작을 제어할 수 있다.
- @Transactional(isolation = Isolation.READ_COMMITTED)
//커밋된 데이터만 다른 트랜잭션에서 조회할 수 있도록 보장
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateAccountBalance(String accountId, double amount) {
// 계좌 잔액 업데이트 작업 수행
}
3. propagation
- 트랜잭션 동작 도중 다른 트랜잭션을 호출할 때, 어떻게 할 것인지 설정
- 기본값 : REQUIRED
- REQUIRED로 설정하면 기존 트랜잭션이 있는 경우 해당 트랜잭션에 참여하고, 없는 경우 새로운 트랜잭션을 생성한다.
- REQUIRES_NEW, NESTED, SUPPORTS, NOT_SUPPORTED, NEVER 등이 있다.
- @Transactional(propagation = Propagation.REQUIRED)
4. timeout
- 트랜잭션의 제한 시간을 설정
- 시간은 초 단위로 설정하며, 설정한 시간을 초과할 경우 트랜잭션이 롤백된다다.
응용 프로그램에 트랜잭션 타임아웃 정책이 있을 경우 유용하게 사용할 수 있다.
- 기본값: -1(무제한)
- @Transactional(timeout = 60)
참고해서 개발할 때 적용해보세요 !
클래스 단위로 트랜잭션을 설정하는것보다는
필요한 메소드 단위에서 설정하는게 더 좋은것 같습니다
'DB' 카테고리의 다른 글
[ERD] 이클립스 ER Master 사용법 그리고 ERD 추출, JAVA DOC 추출시 인코딩 에러 해결 (1) | 2024.07.11 |
---|---|
[DB] 트랙잭션(Transaction)개념과 접근방식 (2) | 2024.03.05 |
[DB/SQL] 뷰(View) 그리고 프로시저(Procedure) 개념 (3) | 2024.02.29 |
[SQL] MySql에서 함수를 사용하는것과 사용하지 않는것에 대한 속도 차이 (4) | 2024.01.07 |
[DB] DBeaver(디비버)로 Tibero(티베로) 연결하기 (2) | 2023.12.11 |