JAVA/Spring
[Spring] 스프링 트랜잭션과 동작방식에 대한 간략한 기록
JongHyun99
2022. 6. 20. 11:38
728x90
스프링의 데이터베이스 처리 중 작동 방식에 대해 컨트롤할 수 있는 트랜잭션 기능을 제공합니다. 동작방식은 아래 4가지와 같습니다.
- 전파: 로직 중 예외가 발생했을 때 예외까지 변경된 데이터가 되돌아가야(RollBack) 할지, 저장되어야 할지 (Commit)
- 제한시간: 수행하는데 걸리는 시간을 설정
- 격리수준: 실시간으로 수정 중인 다른 데이터를 조회했을 때 수정된 상태로 보여야 하는지, 트랜잭션 간의 작업의 연관성에 개입
- 읽기전용: 데이터 조작을 방지
트랜잭션 전파 (PROPAGATION)
작업 A와 B가 있을 때 두 작업 간의 처리방식에 대한 설정입니다.
- PROPAGATION_REQUIRED
- A 작업이 수행된 후 B는 새로운 트랜잭션을 만들지 않고 A에 트랜잭션에 참여합니다.
- A와 B는 하나의 트랜잭션으로 묶여 둘 중 하나에서 예외가 발생하면 모두 취소됩니다.
- PROPAGATION_REQUIRES_NEW
- A와 B는 서로 무관한 트랜잭션으로 새로 생성하게 됩니다.
- 서로 독자적인 트랜잭션으로 하나의 트랜잭션이 수행되면 다른 트랜잭션에서 예외가 발생해도 이전 트랜잭션에 영향을 끼치지 않습니다.
- PROPAGATION_NOT_SUPPORTED
- 트랜잭션을 설정하지 않습니다.
- 단순 데이터 조회같은 트랜잭션이 필요없는 경우라면 이 속성을 사용할 수 있습니다.
- PROPAGATION_MANDATORY
- 기존 트랜잭션이 있다면 참여하고, 없다면 예외를 발생시킵니다.
- 혼자 트랜잭션을 진행시키면 안되는 로직에 사용할 수 있습니다.
- PROPAGATION_NESTED
- 기존 트랜잭션의 자식으로 생성합니다.
- REQUIRES_NEW와는 다르게 부모 트랜잭션의 예외는 자식 트랜잭션에 영향을 주지만 그 반대로 자식의 예외는 부모에게 영향을 주지 않습니다.
- 예를들어 자식 서비스의 로깅같은 트랜잭션이 있을 때 이가 실패되도 부모의 작업이 롤백되서는 안되므로 이 속성을 이용할 수 있습니다.
트랜잭션 격리수준 (ISOLATION)
모든 트랜잭션은 격리수준을 가지고 있습니다. 서비스에서 여러 트랜잭션이 동시에 진행될 수 있는데, 이 때 발생할 수 있는 데이터의 정합성 문제나 성능에 관여되는 트랜잭션 독립, 순차적인 레벨을 관리할 수 있습니다.
- ISOLATION_DEFAULT
- DB 드라이버의 기본 설정을 따릅니다.
- 대부분 READ_COMMITED를 기본 격리수준으로 가집니다.
- READ_COMMITED: 커밋된 것들만을 읽습니다.
- ISOLATION_READ_UNCOMMITTED
- 데이터 커밋 여부와 상관 없이 변경된 데이터를 읽어옵니다.
- 데이터의 정합성이 깨질 우려가 있습니다. (하나의 트랜잭션에서 같은 SELECT가 다른 결과를 가져올 수 있음)
- 가장 낮은격리수준이지만 가장 빠르기 때문에 성능이 중요한 상황에 사용합니다.
- ISOLATION_READ_COMMITTED
- 대부분 default 속성으로 지니며 가장 많이 사용됩니다.
- 트랜잭션이 이미 지나간 뒤 커밋이 완료된 내용만을 읽습니다.
- 이미 트랜잭션이 지나간 뒤 수정되어 순차가 다를 경우 처음 트랜잭션이 읽은 내용과 다를 수 있습니다.
- ISOLATION_REPEATABLE_READ
- 한번 읽은 트랜잭션이 수정되지 않도록 막아줍니다.
- 하지만 새로 insert하는 것을 막아주지 않습니다.
- SERIALIZABLE
- 가장 강력한 격리수준으로 트랜잭션을 순차적으로 진행시켜줍니다.
- 여러 트랜잭션이 동시에 같은 테이블의 정보를 엑세스할 수 없습니다.
- 성능이 안좋아 꼭 필요한 경우에만 사용합니다.
롤백/커밋 예외
추가적으로 롤백/커밋에 예외를 둘 수 있습니다.
- noRollbackFor: 특정 예외 발생 시 rollback하지 않는다.
- rollbackFor : 특정 예외 발생 시 rollback한다.
예시
@Transactional(noRollbackFor = { ExceptionA.class, ExceptionB.class })
public void insertItem() {
...
}