
Transaction이란?
- DB 상태를 변화시키기 위해 수행하는 작업의 논리적 단위
- DB 상태를 변화시킬 수 있는 행동
- Select
- DML - Update, Insert, Delete
- DDL - Create, Drop
여기서 select는 왜 트랜잭션 단위로 묶일까?
Select가 데이터 베이스 상태를 변화시킬 수 있는 것은 아니다. 그러나 트랜잭션으로 관리하면 좋다.
왜냐하면 Select를 수행하는 동안 해당 테이블을 업데이트 할 수 없도록 하기 위함이다.
보통 Select 한 결과를 update, insert, delete의 매개변수로 이용할 수 있기 때문에 트랜잭션으로 관리한다.
트랜잭션의 성질
- ACID
원자성- 한 트랜잭션 내에 실행한 연산들은 하나의 작업으로 봄 ( all or nothing 모두 성공하거나 실패)일관성- 작업 처리 결과 항상 일관성이 있어야 한다. 데이터베이스 상태를 일관성 있게 유지독립성- 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않아야 함지속성- 트랜잭션 작업이 성공하면 결과는 영구적으로 반영되어야 함
- 트랜잭션 내에서 실행한 연산들은
- 모두 성공하면 commit 됨.
- 하나라도 실패하면 성공한 연산이 있더라도 모두 roll back 되어야 함.
스프링에서의 트랜잭션
- 일반적으로
하나의 서비스 로직 단위이다. - 하나의 Service 함수는 다양한 DAO 함수 호출을 통해 하나의 트랜잭션을 구성한다.
- 예외 발생 시 예외 발생 전에 실행된 모든 DAO 명령들을 롤백하거나, 정상동작한 경우 커밋할 수 있다.
- 정상 여부에 따라
Commit또는Rollback함- 정상 여부는
RuntimeException발생했는지 기준으로 결정됨 - RuntimeException 외 다른 Exception에도 트랜잭션 롤백처리를 적용하고 싶으면 @Transactional의
rollbackFor속성을 활용할 수 있음 - 자세한건 https://jisoooit.tistory.com/155 참고!!
- 정상 여부는
- 정상 여부에 따라
- Test 클래스에서의 트랜잭션
- @Transaction을 붙여줄 경우 메서드마다 데이터를 롤백한다.
AUTO_INCREMENT된 값은 트랜잭션 외부에서 작동하므로 롤백되지 않는다.
- 트랜잭션 적용 방법
@Transaction어노테이션을 트랜잭션 관리하고 싶은 메서드 단에 작성한다.- 클래스 단이 아니라 DAO를 통해 CRUD를 실행하는 서비스 단에 붙여주는 것이 좋음
- 클래스 단에 작성할 경우, DB 이외의 다른 외부 자원을 사용하는 경우 DB까지 영향을 미칠 수 있다.
- 각 메서드와 상황에 따라 트랜잭션을 어떻게 처리할지 달라지기 때문에 메서드단에 작성!
- 만약 DB에 있는 데이터를 Read만 하는 경우에도 필요하면
@Transcational (readOnly = true로 작성 가능 - 주의할 점
- 서비스 로직에서 외부 API를 호출하거나, DB 이외의 외부 자원에 접근하는 경우 트랜잭션으로 묶는 것이 좋지 않음
- 다수 요청이 같은 트랜잭션으로 묶이면 동일한 DB커넥션이 오랫동안 물려있어서 DB커넥션 타임아웃과 같은 이슈가 발생할 수 있다.
- JPA는 CRUD 자체적으로
@Transactional을 가짐 ( 각 메서드에 타고 들어가보면 @Transactional붙어있다)
@Trasnactional 옵션
1) isolation
여러개의 트랜잭션이 동시에 데이터베이스에 접근했을때 해당 트랜잭션들을 어떻게 처리할 것인지에 대한 설정이다.
기본값은 default로 DB의 기본값을 따라간다.
옵션
DEFAULT- 기본 격리 수준, DB 격리수준을 따른다. [level0]READ UNCOMMITTED- 커밋되지 않은 데이터를 읽을 수 있게 허용한다. Dirty Read가 발생할 수 있다.[level1]READ COMMITTED- 커밋된 데이터에 대해 읽기를 허용한다. Non - repeatable read, phantom read발생할 수 있다.[level2]- REPEATABLE READ - 동일한 필드에 대해 다중 접근시 모두 동일한 결과를 보장한다.[level3]
SERIALIZABLE- 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 shared lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정 및 입력이 불가능하다. 가장 높은 격리, 성능 저하의 우려가 있다.[level4]
격리 수준에 따른 문제점
| Isolation Level | Dirty Read | Non - Reapatable Read | Phantom Read |
| Read Uncommitted | O | O | O |
| Read Committed | - | O | O |
| Repeatable Read | - | - | O |
| Serializable | - | - | - |
Dirty Read
트랜잭션 1이 수정중인 데이터를 트랜잭션 2가 읽을 수 있음
만약 트랜잭션 1의 작업이 정상 커밋되지 않아 롤백되면 트랜잭션 2가 읽었던 데이터는 잘못된 데이터가 되는 것
(데이터 정합성에 어긋남)
Non-repeatable read
트랜잭션 1이 회원 A를 조회중에 트랜잭션 2가 회원 A의 정보를 수정하고 커밋한다면 트랜잭션 1이 다시 회원 A를 조회했을 때는 수정된 데이터가 조회됨 (이전 정보를 다시 조회할 수 없음)
이처럼 반복해서 같은 데이터를 읽을 수 없는 경우임
Phantom read
트랜잭션 1이 10살 이하의 회원을 조회했는데 트랜잭션 2가 5살 회원을 추가하고 커밋하면 트랜잭션 1이 다시 10살 이하 회원을 조회했을 때 회원 한명이 추가된 상태로 조회됨
이처럼 반복 조회시 결과집합이 달라지는 경우
트랜잭션 격리 수준의 필요성
당연히 레벨이 높아질 수록 데이터 무결성을 유지할 수 있음
하지만 무조건적인 상위 레벨을 사용할 시 Locking으로 동시에 수행되는 많은 트랜잭션들이 순차적으로 처리하게 되면서 DB의 성능은 떨어지게 되고 비용이 높아진다. 그렇다고 Locking의 범위를 줄이게 되면 잘못된 값이 처리될 여지도 발생함 그러므로 최대한 효율적인 방안을 찾아 상황에 맞게 사용하는 것이 중요하다.
2 ) Propagation
트랜잭션 동작 도중 다른 트랜잭션을 호출할 때 어떻게 할 것인지를 지정하는 옵션이다.
옵션
REQUIRED (default)- 이미 진행중인 트랜잭션이 있다면 해당 트랜잭션 속성을 따르고, 없다면 새로운 트랜잭션을 생성한다.REQUIRES_NEW- 항상 새로운 트랜잭션을 생성한다. 이미 진행중인 트랜잭션이 있다면 잠깐 보류하고 해당 트랜잭션 작업을 먼저 진행한다.SUPPORT- 이미 진행중인 트랜잭션이 있다면 해당 트랜잭션 속성을 따르고, 없다면 트랜잭션을 설정하지 않는다.NOT_SUPPORT- 이미 진행중인 트랜잭션이 있다면 해당 트랜잭션 속성을 따른다.MANDATORY- 이미 진행중인 트랜잭션이 있어야만 작업을 수행하고, 없다면 Exception을 발생시킨다.NEVER- 트랜잭션이 진행중이지 않을때 작업을 수행하고, 있다면 Exception을 발생시킨다.NESTED- 진행중인 트랜잭션이 있다면 중첩된 트랜잭션이 실행되고, 없다면 REQUIRED와 동일하게 실행됨 ( 사용을 권하지 않고 있음 )
3) noRollbackFor
특정 예외 발생시 rollback하지 않는다.
4) rollbackFor
특정 예외 발생 시 강제로 rollback한다.
3,4번 자세한건 https://jisoooit.tistory.com/155 참고!!
4) timeout
- 지정한 시간 내에 메서드 수행이 완료되지 않으면 rollback한다.
- -1일 경우 timeout을 사용하지 않는다는 의미이다.(default)
5) readOnly
- 트랜잭션을 읽기 전용으로 설정한다.
- true시 insert, update, delete 실행 시 예외 발생한다.
- Default = false
@Transactional이 작동하지 않는 경우
1. 메서드 접근 제어자가 public이 아닌 경우
트랜잭션 매니저가 @Transactional을 관리 불가능하다.
2. 같은 클래스에서, @Transactional이 없는 메서드에서 @Transcational이 붙어있는 다른 메서드를 호출하는 경우
스프링에서는 인스턴스에서 처음 호출하는 메서드나 클래스 속성을 따라간다.
트랜잭션으로 처리하는 방법
- 호출하는 상위 메서드에 @Transacatioanl 붙임
- 클래스 분리
'Spring' 카테고리의 다른 글
| [ spring ] @Component 와 @Configuration (0) | 2022.12.16 |
|---|---|
| [ Spring ] 의존성 주입 방법 (feat.lombok) (0) | 2022.11.23 |
| [ Spring ] Swagger이란 (0) | 2022.11.17 |
| [ Spring ] restTemplate (0) | 2022.11.11 |
| [spring] 어노테이션 (Annotaions) (0) | 2022.11.04 |