@Transactional
@Transactrional이란?
@Transactional은 스프링 프레임워크에서 제공하는 애노테이션으로, 데이터베이스 트랜잭션을 관리하는 데 사용됩니다. 이 애노테이션은 메서드 레벨 또는 클래스 레벨에서 사용할 수 있으며, 트랜잭션의 범위와 특성을 정의합니다.
@Transactional 애노테이션을 사용하면 다음과 같은 역할을 수행할 수 있습니다:
트랜잭션 관리: @Transactional 애노테이션이 적용된 메서드는 트랜잭션 내에서 실행됩니다. 스프링은 트랜잭션의 시작과 종료, 롤백 또는 커밋과 같은 트랜잭션 관리 작업을 자동으로 처리합니다. 이를 통해 개발자는 명시적으로 트랜잭션을 제어하는 코드를 작성하지 않고도 편리하게 트랜잭션을 사용할 수 있습니다.
롤백 처리: 기본적으로 @Transactional 애노테이션은 예외가 발생하면 롤백을 수행하여 트랜잭션 내에서 실행된 작업을 이전 상태로 되돌립니다. 이를 통해 데이터 일관성과 안전성을 유지할 수 있습니다. 또한, @Transactional 애노테이션의 rollbackFor 속성을 사용하여 롤백할 예외를 지정할 수도 있습니다.
트랜잭션 경계 설정: @Transactional 애노테이션을 사용하여 메서드의 트랜잭션 경계를 정의할 수 있습니다. 예를 들어, 메서드 실행 시 새로운 트랜잭션을 시작하거나, 이미 진행 중인 트랜잭션이 있으면 해당 트랜잭션에 참여하도록 설정할 수 있습니다. 또한, 트랜잭션의 격리 수준과 타임아웃 등을 설정할 수도 있습니다.
트랜잭션 속성 제어: @Transactional 애노테이션의 다양한 속성을 사용하여 트랜잭션의 동작 방식을 제어할 수 있습니다. 예를 들어, 트랜잭션을 읽기 전용으로 설정하거나, 트랜잭션의 전파 동작을 변경하거나, 트랜잭션의 이름을 지정할 수 있습니다. 이를 통해 다양한 트랜잭션 시나리오에 대응할 수 있습니다.
@Transactional 애노테이션은 스프링의 트랜잭션 관리 기능을 활용하여 데이터베이스 트랜잭션을 쉽게 사용할 수 있도록 해줍니다. 이를 통해 개발자는 복잡한 트랜잭션 관리 코드를 작성하지 않고도 트랜잭션 처리를 간단하게 수행할 수 있습니다.
@Transactional 작동방식
@Transactional 애노테이션은 스프링의 트랜잭션 관리 기능을 적용하기 위해 사용됩니다. 이 애노테이션이 적용된 메서드 또는 클래스는 트랜잭션 경계를 설정하고, 트랜잭션의 시작, 커밋, 롤백 등의 작업을 자동으로 처리합니다.
@Transactional 애노테이션의 동작 원리는 다음과 같습니다:
프록시 생성: @Transactional 애노테이션이 적용된 빈(Bean) 객체를 스프링은 프록시(proxy) 객체로 감싸게 됩니다. 이를 통해 메서드 호출 전후에 트랜잭션 관련 작업을 수행할 수 있습니다.
트랜잭션 시작: @Transactional 애노테이션이 적용된 메서드가 호출되면, 스프링은 트랜잭션을 시작합니다. 이를 위해 적절한 트랜잭션 매니저(Transaction Manager)를 사용하고, 트랜잭션 경계를 설정합니다.
메서드 실행: 트랜잭션 내에서 @Transactional 애노테이션이 적용된 메서드의 실행이 시작됩니다. 메서드는 일반적인 방식으로 코드를 실행하며, 트랜잭션과 관련된 작업을 수행합니다. 이 때, 트랜잭션 관리자는 트랜잭션 경계를 유지하면서 데이터베이스 연산을 수행합니다.
커밋 또는 롤백: 메서드 실행이 정상적으로 완료되면, 스프링은 트랜잭션을 커밋합니다. 이는 메서드 내에서 수행된 데이터베이스 변경 사항을 영구적으로 저장하는 작업입니다. 그러나 예외가 발생한 경우, 스프링은 트랜잭션을 롤백하여 이전 상태로 되돌립니다. 이를 통해 데이터 일관성을 유지하고 예외 상황을 처리할 수 있습니다.
@Transactional 애노테이션은 스프링의 AOP(Aspect-Oriented Programming) 기능을 활용하여 동작합니다. AOP는 프록시 객체를 생성하여 메서드 호출 전후에 추가 동작을 수행하는 기술입니다. 스프링은 @Transactional 애노테이션을 해석하여 프록시 객체를 생성하고, 트랜잭션 관련 작업을 프록시 객체의 메서드에 적용합니다.
또한, @Transactional 애노테이션은 클래스 레벨에도 적용할 수 있습니다. 이 경우, 클래스 내의 모든 메서드에 트랜잭션 기능이 적용되며, 메서드에 별도의 @Transactional 애노테이션이 적용되지 않은 경우에도 클래스 수준의 설정이 적용됩니다.
이렇게 @Transactional 애노테이션을 사용하여 트랜잭션 관리를 수행하면, 개발자는 트랜잭션 경계 설정 및 트랜잭션의 커밋 또는 롤백과 같은 작업에 대한 세부적인 관리를 할 필요 없이, 간편하게 트랜잭션 처리를 수행할 수 있습니다.
여러 AP에서 하나의 DB접근 시 @Transactional 작동 방식
여러 개의 애플리케이션(AP)이 하나의 데이터베이스(DB)에 접근할 때 @Transactional 애노테이션은 다음과 같은 방식으로 작동합니다:
독립적인 트랜잭션: 각 애플리케이션은 독립적인 트랜잭션을 가집니다. 즉, 각 애플리케이션은 자체적으로 트랜잭션을 시작하고 커밋 또는 롤백할 수 있습니다. @Transactional 애노테이션이 적용된 메서드나 클래스 내에서 수행되는 데이터베이스 연산은 해당 애플리케이션의 트랜잭션 내에서 처리됩니다.
공유 데이터베이스 커넥션: 여러 개의 애플리케이션은 하나의 데이터베이스에 접근하기 때문에 동일한 데이터베이스 커넥션을 공유합니다. 데이터베이스 커넥션 풀을 사용하여 애플리케이션은 필요할 때마다 커넥션을 얻고 반환합니다. 이렇게 공유된 커넥션을 사용하여 각 애플리케이션의 트랜잭션 작업이 처리됩니다.
격리 수준 설정: @Transactional 애노테이션을 사용하여 격리 수준을 설정할 수 있습니다. 격리 수준은 동시에 실행되는 트랜잭션 간의 데이터 일관성과 격리 수준을 조정하는 데 사용됩니다. 여러 애플리케이션이 동시에 작업을 수행할 때 격리 수준을 적절히 설정하여 데이터의 정확성과 일관성을 유지할 수 있습니다.
트랜잭션 관리자 설정: 각 애플리케이션은 독립적인 트랜잭션 관리자를 가질 수 있습니다. 트랜잭션 관리자는 트랜잭션의 시작, 커밋, 롤백 등을 처리하는 역할을 담당합니다. 각 애플리케이션은 자체적으로 트랜잭션 관리자를 구성하여 원하는 방식으로 트랜잭션을 관리할 수 있습니다.
주의할 점은 다수의 애플리케이션이 하나의 데이터베이스를 공유한다는 것입니다. 동시에 여러 애플리케이션이 동일한 데이터를 변경할 수 있기 때문에, 데이터의 일관성과 무결성을 보장하기 위해서는 적절한 트랜잭션 격리 수준과 충돌 방지 기법을 사용해야 합니다. 또한, 트랜잭션 범위를 적절하게 설정하여 트랜잭션의 지연 시간을 최소화하고 동시성을 향상시킬 수 있습니다.
다수의 애플리케이션이 하나의 데이터베이스를 조작하게 될 때 동시에 여러 요청이 들어오는 상황에서 데이터의 일관성과 무결성을 보장하기 위해 다음과 같은 방법들을 고려할 수 있습니다:
트랜잭션 격리 수준 설정: 데이터베이스의 격리 수준을 설정하여 동시에 실행되는 트랜잭션 간의 격리 수준을 조정할 수 있습니다. 격리 수준은 트랜잭션 간의 데이터 접근 및 변경 시 발생할 수 있는 문제들을 관리하며, 더 높은 격리 수준은 데이터 일관성을 보다 강력하게 유지할 수 있습니다.
트랜잭션 범위 최소화: 트랜잭션의 범위를 최소화하여 트랜잭션을 짧고 빠르게 유지합니다. 이는 동시에 데이터를 조작하는 애플리케이션들이 서로의 작업에 영향을 미치는 시간을 최소화하고, 데이터의 일관성을 보다 잘 유지할 수 있도록 도와줍니다.
동시성 제어: 동시에 데이터를 조작하는 애플리케이션들 사이에서의 충돌을 방지하기 위해 동시성 제어 기법을 사용할 수 있습니다. 예를 들어, 락(Lock) 메커니즘을 활용하여 여러 애플리케이션이 동시에 동일한 데이터를 변경하지 못하도록 제어할 수 있습니다.
무결성 제약 조건 설정: 데이터베이스에 무결성 제약 조건(Constraints)을 설정하여 데이터의 일관성을 유지할 수 있습니다. 이는 데이터베이스 수준에서 데이터의 유효성을 검증하고, 잘못된 데이터의 입력을 방지함으로써 데이터의 무결성을 보호합니다.
메시지 큐 또는 이벤트 버스 사용: 동시에 들어오는 요청을 조정하기 위해 메시지 큐나 이벤트 버스와 같은 중앙 집중식 메커니즘을 사용할 수 있습니다. 애플리케이션들은 요청을 큐 또는 이벤트로 보내고, 순차적으로 처리될 수 있도록 합니다. 이를 통해 충돌이나 데이터 일관성 문제를 효과적으로 관리할 수 있습니다.
교착 상태(Deadlock) 방지: 교착 상태는 여러 애플리케이션이 동시에 데이터를 조작하다가 무한 대기 상태에 빠지는 상황을 말합니다. 교착 상태를 방지하기 위해 교착 상태 탐지 알고리즘을 사용하거나, 트랜잭션 타임아웃을 설정하여 대기 시간을 제한할 수 있습니다.
이러한 방법들을 적절히 조합하여 데이터의 일관성과 무결성을 보장하고, 다수의 애플리케이션이 동시에 데이터베이스
를 조작할 때 충돌이나 데이터 손상을 최소화할 수 있습니다.
@Transactional 서로 다른 AP에서 하나의 DB data에 접근 시
@Transactional 애노테이션을 사용하여 메서드나 클래스에 트랜잭션을 적용했을 때, 다른 애플리케이션에서 해당 데이터에 접근할 수 있는지 여부는 사용하는 데이터베이스와 해당 데이터베이스의 격리 수준에 따라 달라집니다.
스프링 부트의 @Transactional 애노테이션은 기본적으로 데이터베이스 트랜잭션을 지원합니다. 대부분의 데이터베이스는 트랜잭션 격리 수준을 제공하며, 격리 수준에 따라 데이터의 동시 접근이 가능하거나 제한될 수 있습니다.
일반적으로 격리 수준에는 다음과 같은 네 가지 수준이 있습니다:
READ UNCOMMITTED (최소 격리 수준): 다른 트랜잭션에서 변경 중인 데이터에 접근이 가능합니다. 따라서 다른 애플리케이션에서도 해당 데이터에 접근할 수 있습니다. 이 수준은 데이터 무결성을 보장하지 않으며, 데이터의 일관성에 문제가 발생할 수 있습니다.
READ COMMITTED: 커밋된 데이터만 접근 가능합니다. 다른 트랜잭션에서 변경 중인 데이터에는 접근할 수 없습니다. 따라서 다른 애플리케이션에서는 해당 데이터에 접근할 수 없습니다.
REPEATABLE READ: 한 트랜잭션 내에서 조회한 데이터는 트랜잭션이 끝날 때까지 일관된 값을 유지합니다. 따라서 동일한 애플리케이션에서는 조회한 데이터에 접근할 수 있지만, 다른 애플리케이션에서는 해당 데이터에 접근할 수 없습니다.
SERIALIZABLE (최대 격리 수준): 가장 높은 격리 수준으로, 동시에 실행되는 모든 트랜잭션을 순차적으로 실행합니다. 이 수준에서는 동시 접근이 일어나지 않기 때문에 다른 애플리케이션에서도 해당 데이터에 접근할 수 없습니다.
따라서, 격리 수준이 REPEATABLE READ 이상인 경우에는 다른 애플리케이션에서는 @Transactional 애노테이션이 적용된 메서드로부터 변경 중인 데이터에 접근할 수 없습니다. 하지만 격리 수준이 READ UNCOMMITTED인 경우에는 다른 애플리케이션에서도 해당 데이터에 접근할 수 있습니다.
격리 수준은 데이터베이스마다 다를 수 있으며, 일반적으로 데이터베이스 설정이나 트랜잭션 매니저 설정을 통해 조정할 수 있습니다. 따라서 애플리케이션 간의 데이터 접근 제한을 설정하려면 데이터베이스의 격리 수준을 확인하고 필요에 따라 변경해야 합니다.
@Transactional 격리 수준 default는?
Spring Framework에서 @Transactional 애노테이션의 기본 격리 수준은 데이터베이스마다 다를 수 있습니다. 하지만 일반적으로 Spring의 트랜잭션 관리자인 PlatformTransactionManager의 기본 격리 수준은 "DEFAULT"입니다.
"DEFAULT" 격리 수준은 실제로 데이터베이스 공급업체에 의해 결정되는 데이터베이스의 기본 격리 수준을 사용합니다. 각 데이터베이스 시스템은 기본적으로 다른 격리 수준을 가질 수 있으며, 예를 들어 Oracle의 기본 격리 수준은 "READ COMMITTED"이고, MySQL의 기본 격리 수준은 "REPEATABLE READ"입니다.
따라서 @Transactional 애노테이션을 사용할 때 기본적으로 데이터베이스의 기본 격리 수준을 따르게 됩니다. 만약 특정한 격리 수준을 명시적으로 지정하고 싶다면, isolation 속성을 사용하여 원하는 격리 수준을 명시적으로 지정할 수 있습니다. 예를 들어 @Transactional(isolation = Isolation.READ_COMMITTED)과 같이 사용할 수 있습니다.