트랜잭션(Transaction)
정의
데이터베이스서 수행되는 작업의 단위를 말한다. 이는 "원자성(Atomicity)",일관성(Consistency)","고립성(lsolation)",
"지속성(Durability)"을 준수하는 작업의 단위다.
- 원자성(Atomicity) : 전부 실행되거나 전부 실행되지 않는다.
- 일관성(Consistency): 데이터베이스가 트랜잭션이 실행이 되더 라도 항상 일관된 상태를 유지하는 것
- 고립성(lsolation) : 동시에 여러 트랜잭션이 실행 되더라고 서로가 영향을 미치지않고 독립적으로 실행되는것
- 지속성(Durability): 트랜잭션이 성공적으로 완료되면 결과가 영구적으로 저정되는 것
트랜잭션 전파
트랜잭션 전파란 트랜잭션의 경계에서 이미 진행중인 트랜잭션이 있을때 또는 없을 대 어떻게 동작할 것인가를 결정하는 방식이다.
그림과 같이 A.method 내에서 트랜잭션을 가지는 b.method가 시작된다고 해보자 그럼 b메소드는 기존 트랜잭션에 참여하는것일까? 아니면 새로운 트랜잭션을 만들어서 하는것일까. 그것은 어떤 전파 속성을 사용 하는지에 따라서 결정된다
트랜잭션 전파 속성
- PROPAGATION_REQUIRED : 이미 시작된 트랜잭션이 있다면 그 트랜잭션에 참여한다. 즉 B메소드는 트랜잭션을 사용하지않고 A에 같이 하나의 트랜잭션으로 사용되며 B에서 성공이 됬어도 A가 오류가나서 롤백을 한다면 B메소드도 롤백된다.
- PROPAGATION_REQUIRES_NEW : 항상 새로운 트랜잭션을 만들어 사용한다. 즉 B메소드 트랜잭션과 A트랜잭션이 따로 만들어지며 사용되며, B가 성공하고 A가 실패한다면 B는 DB에 저장되지만 A는 저장되지않는다.
- PROPAGATION_NOT_SUPPORTED : 트랜잭션 없이 동작하도록 만드는 옵션
사용법
@Transactional(propagation = Propagation.REQUIRED)
public void methodWithTransactionPropagation() {
// 트랜잭션 처리 내용
}
격리수준
동시에 여러 트랜잭션이 실행될 때, 이들간에 얼마나 서로 영향을 주고받는지 결정하는것이다.
- READ_UNCOMMITTED : 하나의 트랜잭션이 아직 커밋되지 않은 다른 트랜잭션의 변경 상항을 읽을수 있다.
- READ_COMMITTED : 커밋된 데이터만 읽을수 있다.
- REPEATBLE_READ : 한 트랜잭션 내에서 같은 쿼리를 실행하더라고 결과가 항상 같아야한다.
- SERIALIZABLE : 가장 높은 격리 수준으로, 모든 트랜잭션은 순차적으로 샐행되는 것처럼 처리된다.
이런 격리수준을 가지고 있지만 .기본적으로는 DEFAULT로 데이터 베이스의 기본 격리수준을 가지고있다.
사용법
@Transactional(isolation = Isolation.READ_COMMITTED)
public void myTransactionalMethod() {
// 트랜잭션 수행 내용
}
제한 시간
트랜잭션에서는 제한시간들 둘수있다. 설정한 시간내에만 트랜잭션을 사용하며 이시간 보다 넘어갈 경우에는 롤백
사용법
@Transactional(timeout = 5000) // 5초
public void myTransactionalMethod() {
// 트랜잭션 수행 내용
}
읽기 전용
읽기 전용으로 설정해두면 트랜잭션내에서 데이터를 조작하는 시도를 막아줄수있다.
get 같은 메소드를 만들어서 사용할때 단지 조회를 위한 메소드며, 수정이 될일은 없을것이다. 그래서 읽기 전용 옵션을 사용하면, DAO에 따라서 성능향상될수있다. (기본값은 false로 되어 있다.)
사용법
@Transactional(readOnly = true)
public void readOperation() {
// 읽기 전용 트랜잭션 수행 내용
}
@Transactional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional{
...
}
@Transactional 을 정의한 코드이다.
- @Target(...) : 메소드 타입(클래스 ,인터페이스)처럼 한개 이상의 대상을 지정가능
- @Retention(...) : 애노테이션이 언제까지 유지되는가를 지정한다. 이렇게 설정되면 런라임 때도 얻을수있다.
- @Inherited : 삭송을 통해서도 애노테이션 정보를 얻을수있게한다.
대채 정책
[1]
public interface Service {
[2]
void method();
[3]
void method2();
}
[4]
public class ServiceImpl implements Service{
[5]
public void method() {}
[6]
public void method2() {}
}
만약 인터페이스를 두고 서비스를 구현했다면 위 코드와 같은 순서대로 적용된다.
- [1] 인터페이스 클래스 레벨을 먼저 확인한다. 있다면 사용,없다면
- [2] ,[3] 인터페이스 메소드에 있는지 확인한다. 있다면 사용,없다면
- [4] 인터페이스를 구현한 클래스레벨을 확인한다. 있다면 사용,없다면
- [5],[6] 구현한 메소드를 확인한다.
이런식으로 적용된다. 기본적으로는 클래스 레벨에 트랜잭션을 부여하고 읽기 옵션같은 메소드가 필요한곳에 따로 @Transaction(readOnly =ture)형식으로 사용하는것이 좋을것같다.
테스트에서 사용
테스트 에서 트랜잭션을 사용 하게되면 기본적으로 롤백을 하게된다.
- 커밋(COMMIT) : 데이터를 DB에 저장한다.
- 롤백(ROLLBACK) : 오류 시에 기존의 상태로 돌아간다
직접 DB에 데이터가 담기는 것을 보고싶다면
@Test
@Rollback(false)
void RollbackTest(){
...
}
코드와 같이 클래스 레벨에 적용하는것보다는 메소드 레벨에 적용하여 사용하는것을 권장한다.
'Spring > spring' 카테고리의 다른 글
[Spring] 스프링에서의 필터(filter)와 인터셉터(Interceptor) (1) | 2024.02.06 |
---|---|
[스프링] AOP(Aspect-Oriented-Programming)이해 (0) | 2023.11.22 |
스프링 서비스 추상화 (1) | 2023.11.19 |
스프링 예외처리(Exception) (0) | 2023.11.17 |
스프링 오브젝트 와 의존관계 (1) | 2023.11.14 |