[F-Lab 66해빗 페이백 챌린지 ]

[F-Lab 모각코 페이백 22일차] 스프링 트랜잭션 (Spring Transaction)

everydeveloper 2023. 6. 7. 23:05

학습 목표

  • 스프링 트랜잭션 (Spring Transaction)

 

TIL

  • 스프링 트랜잭션

 

 

스프링 트랜잭션 (Spring Transaction)

Spring Framework에서 제공하는 Transaction 관리는 웹 애플리케이션에서 데이터 일관성을 보장하는 매우 중요한 부분입니다. 

Spring Transaction은 두 가지 방식으로 처리할 수 있습니다.

1. 선언적 트랜잭션(Declarative Transaction): 이 방식은 XML 설정이나 어노테이션(@Transactional)을 통해 트랜잭션을 관리합니다. 이는 코드와 설정을 분리하므로 코드의 가독성을 높이고 유지 보수를 용이하게 합니다. `@Transactional` 어노테이션을 메소드나 클래스에 추가하여 해당 메소드나 클래스에 포함된 작업이 하나의 트랜잭션으로 처리되도록 합니다.

2. 프로그래밍 방식의 트랜잭션(Programmatic Transaction): `TransactionTemplate` 또는 `PlatformTransactionManager` 인터페이스를 직접 사용하여 트랜잭션을 제어합니다. 세밀한 트랜잭션 제어가 필요할 때 사용하지만 코드가 복잡해질 수 있으므로 일반적으로는 선언적 트랜잭션을 선호합니다.

Spring의 트랜잭션 관리는 다양한 데이터 액세스 기술을 투명하게 처리할 수 있습니다. 이러한 기술에는 JDBC, Hibernate, JPA, JDO 등이 있습니다. 또한, 이 기능은 `PlatformTransactionManager` 인터페이스의 구현을 통해 제공되며, 이는 개발자가 트랜잭션 관리 방법을 쉽게 바꿀 수 있도록 돕습니다. 예를 들어, 테스트 환경에서는 `DataSourceTransactionManager`를 사용하고, 프로덕션 환경에서는 JTA를 사용하는 `JtaTransactionManager`로 전환할 수 있습니다.

이외에도, Spring의 트랜잭션 관리 기능은 다양한 트랜잭션 속성을 지원합니다. 이에는 트랜잭션의 전파 행동(예: `PROPAGATION_REQUIRED`, `PROPAGATION_REQUIRES_NEW` 등), 격리 수준(isolation level), 읽기 전용(read-only), 시간 제한(timeout) 등이 포함됩니다. 이런 트랜잭션 속성들은 선언적 트랜잭션의 `@Transactional` 어노테이션을 통해 설정할 수 있습니다.

 

트랜잭션

"트랜잭션(Transaction)"이라는 용어는 데이터베이스 관리 시스템(DBMS)에서 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 지속성(Durability) - 이를 합쳐 ACID 속성이라 부르죠 - 을 만족하는 작업 단위를 의미합니다.

1. 원자성(Atomicity): 트랜잭션 내의 모든 작업이 완전히 수행되거나, 아니면 전혀 수행되지 않아야 함을 의미합니다. 즉, 중간에 실패하면 처음부터 롤백이 되어야 합니다.

2. 일관성(Consistency): 트랜잭션은 시스템의 상태를 한 개의 일관된 상태에서 다른 일관된 상태로 변환시켜야 합니다. 즉, 트랜잭션이 성공적으로 완료되면 언제나 일관성 있는 상태를 유지해야 합니다.

3. 고립성(Isolation): 각 트랜잭션은 서로 독립적으로 실행되어야 함을 의미합니다. 즉, 트랜잭션 수행 시 다른 트랜잭션의 작업이 끼어들지 못하게 해야 합니다.

4. 지속성(Durability): 트랜잭션이 성공적으로 완료되면 그 결과는 영구적으로 반영되어야 합니다.

이와 같은 트랜잭션 관리는 데이터의 정확성과 안정성을 보장하는 매우 중요한 역할을 합니다. 그리고 Spring Framework에서는 이러한 트랜잭션 관리를 추상화하여 다양한 방법으로 쉽게 구현할 수 있도록 도와줍니다. 

데이터 접근 기술에 관계 없이 일관된 프로그래밍 모델을 제공하며, 이를 통해 데이터의 일관성을 유지하고 데이터베이스에서 발생할 수 있는 문제를 최소화하는 데 큰 도움이 됩니다. Spring의 선언적 트랜잭션 관리 방식을 사용하면, 개발자는 비즈니스 로직에 집중하면서 데이터베이스 작업의 복잡성을 크게 줄일 수 있습니다.

 

스프링 트랜잭션 처리 과정

Spring Framework에서 트랜잭션 처리는 다음과 같은 과정을 거칩니다.

1. 트랜잭션 설정:*우선, Spring에서 트랜잭션 관리를 위한 설정을 합니다. XML 또는 Java Config를 이용해 트랜잭션 매니저(Transaction Manager)를 설정하며, 이는 일반적으로 DataSource를 참조합니다. 이 설정에서 트랜잭션 전파, 격리 수준, 타임아웃, 읽기 전용 등과 같은 트랜잭션 속성도 정의할 수 있습니다.

2. @Transactional 사용: 이제 `@Transactional` 어노테이션을 이용해 어느 메서드에서 트랜잭션을 시작할 것인지를 명시합니다. 이 어노테이션은 클래스 또는 메서드 수준에서 적용할 수 있습니다. 클래스 수준에서 적용하면 해당 클래스의 모든 public 메서드가 하나의 트랜잭션으로 취급됩니다.

3. 프록시 객체 생성: Spring AOP(Aspect Oriented Programming)는 `@Transactional` 어노테이션을 이용해 프록시 객체를 생성합니다. 이 프록시 객체는 실제 비즈니스 로직을 실행하기 전후로 트랜잭션 관련 작업을 처리합니다. 이는 트랜잭션을 시작하거나 이미 시작된 트랜잭션에 참여하는 등의 작업을 포함합니다.

4. 트랜잭션 시작: 프록시 객체는 클라이언트가 메서드를 호출할 때 트랜잭션을 시작합니다. 이때, 트랜잭션의 격리 수준, 읽기 전용, 타임아웃 등의 속성이 적용됩니다.

5. 비즈니스 로직 실행: 이제 실제 비즈니스 로직이 실행됩니다.

6. 트랜잭션 커밋 또는 롤백: 비즈니스 로직 실행 후, Spring은 트랜잭션을 커밋하거나 롤백합니다. 만약 비즈니스 로직 실행 중 예외가 발생하면, Spring은 트랜잭션을 롤백합니다. 만약 비즈니스 로직이 성공적으로 실행되면, Spring은 트랜잭션을 커밋합니다.

이런 방식을 통해 Spring은 트랜잭션의 생명주기를 관리하고, 비즈니스 로직 실행 전후로 필요한 트랜잭션 작업을 수행합니다. 이는 트랜잭션 관리를 단순화하고, 개발자가 비즈니스 로직에 집중할 수 있게 하며, 동시에 데이터의 일관성을 보장하는데 매우 중요한 역할을 합니다. 

7. 트랜잭션 완료: 트랜잭션이 성공적으로 커밋되거나, 예외에 의해 롤백된 후에 트랜잭션은 완료됩니다. 이렇게 해서 한 단위의 작업이 완전히 처리되거나, 아니면 전혀 처리되지 않은 상태로 유지되어 데이터의 일관성을 보장하게 됩니다.

스프링 트랜잭션 관리의 가장 큰 장점 중 하나는 다양한 데이터베이스 기술에 대한 일관된 프로그래밍 모델을 제공한다는 점입니다. JDBC, JPA, Hibernate 등 다양한 데이터 액세스 기술을 사용하더라도 동일한 코드와 설정으로 트랜잭션을 관리할 수 있습니다. 이는 개발자가 새로운 기술을 익히는 데 드는 시간과 노력을 줄여주며, 유지 보수도 용이하게 만듭니다. 

이처럼 Spring Framework의 트랜잭션 관리 기능은 데이터 일관성을 보장하면서도 개발자의 부담을 줄이는 강력한 도구입니다.

 

스프링 AOP

AOP(Aspect-Oriented Programming)는 관심사의 분리(Separation of Concerns)를 실현하는 프로그래밍 패러다임 중 하나입니다. 이는 주요 기능(비즈니스 로직)과 이에 수반하는 부가 기능(로깅, 보안, 트랜잭션 등)을 분리하는 데 중점을 둡니다. 

Spring Framework에서의 AOP는 이러한 AOP 개념을 지원하고, 또한 더욱 강력한 기능을 제공합니다. Spring AOP는 프록시 기반의 AOP를 구현하며, 대상 객체를 감싸서 부가 기능을 추가합니다.

Spring AOP의 주요 용어는 다음과 같습니다:

1. Aspect: Aspect는 "관점"이라는 뜻으로, 공통 관심사(Cross-cutting Concerns)를 모듈화한 것입니다. 예를 들어, 로깅이나 보안과 같은 기능이 될 수 있습니다.

2. Join Point: Join Point는 프로그램 실행 중에 Aspect가 적용될 수 있는 지점을 의미합니다. Spring AOP에서 Join Point는 메서드 실행이 주로 됩니다.

3. Advice: Advice는 Aspect의 동작 방식을 나타내며, 언제 어떤 작업을 할 것인지를 정의합니다. Spring AOP에서는 5가지 유형의 Advice를 지원합니다: Before, After, After-returning, After-throwing, Around.

4. Pointcut: Pointcut은 어떤 Join Points(메서드 등)에서 Advice가 실행될 것인지를 결정합니다. AspectJ 표현식 또는 Spring AOP의 API를 이용해 정의할 수 있습니다.

5. Target Object:*부가 기능이 적용되는 대상 객체입니다. Spring AOP에서는 런타임에 프록시를 생성하여 이를 구현합니다.

6. Proxy: Spring AOP는 Target Object에 대한 Proxy를 만들어서 부가적인 기능(Aspect)를 제공합니다. 이 Proxy는 실제 객체를 감싸서 Advice를 적용한 후에 실제 메서드를 호출합니다.

7. Weaving: Weaving은 Aspect를 Target Object에 적용하여 새로운 프록시 객체를 생성하는 과정을 의미합니다. Spring AOP에서는 런타임에 이를 수행합니다.

이런 방식으로 Spring AOP는 로깅, 트랜잭션 관리, 보안 등의 공통적인 기능을 비즈니스 로직으로부터 분리하여 코드의 중복을 줄이고 유지보수를 용이하게 하는 역할을 합니다.

 

프록시 (Proxy)

"프록시"는 대리인이라는 뜻으로, 컴퓨터 과학에서는 어떤 객체가 다른 객체의 인터페이스 역할을 하는 경우를 일컫습니다. 프록시는 원래 객체와 동일한 인터페이스를 제공하므로, 프록시를 사용하는 클라이언트는 프록시가 원래 객체인지 알 수 없습니다. 

프록시 패턴은 객체의 생성이나 접근을 제어하거나 추가적인 작업을 수행하기 위해 사용되며, 이는 디자인 패턴 중 하나입니다.

AOP와 같은 컨텍스트에서의 프록시는 보통 원래 객체 앞에 위치하여 메서드 호출을 가로채고, 필요한 전처리나 후처리 작업을 수행한 후 원래 객체의 메서드를 호출합니다. 이런 방식으로 트랜잭션 관리, 로깅, 보안 검사 등의 부가적인 기능을 제공합니다.

프록시 서버와의 관계를 물어보신다면, 비슷한 개념이긴 합니다. 프록시 서버는 클라이언트와 인터넷 사이에 위치하여 클라이언트의 요청을 대신 처리하는 역할을 합니다. 이 역시 "대리인"이라는 프록시의 본래 의미와 일치합니다.

그러나 주의할 점은, 두 개념이 사용되는 문맥이 다르다는 것입니다. 프록시 서버는 네트워크와 관련된 컨텍스트에서 사용되며, AOP에서의 프록시는 객체 지향 프로그래밍과 디자인 패턴의 컨텍스트에서 사용됩니다.

 

Q.

그 AOP 관점에서 트랜잭션 처리 부분은 공통적이고 부가적인 부분으로 봐서 핵심부분에 트랜잭션 어노태이션을 붙여서 처리를 요청하면 스프링이 그부분은 트랜잭션 처리를 해줘서 롤백이라든가 커밋을 진행해 주겠네 그러면 개발자는 트랜잭션 어노태이션을 적절한 위치에 붙이는 것만 해주면 되서 핵심 로직에 집중 할 수 잇겠네

 

A.

맞습니다. 그렇게 설명해주신 바와 같이, Spring Framework의 트랜잭션 관리는 AOP를 기반으로 합니다. `@Transactional` 어노테이션을 사용하면, 이 어노테이션을 붙인 메서드가 실행될 때 트랜잭션 관리를 위한 공통 기능이 자동으로 적용됩니다. 이 공통 기능은 새로운 트랜잭션을 시작하거나 이미 진행 중인 트랜잭션에 참여하는 것, 메서드 실행이 성공하면 트랜잭션을 커밋하거나 실패하면 롤백하는 것 등을 포함합니다.

따라서 개발자는 트랜잭션 관리를 위한 코드를 작성할 필요 없이 `@Transactional` 어노테이션을 적절한 위치에 붙이는 것만으로 트랜잭션 관리를 할 수 있습니다. 이렇게 함으로써 개발자는 핵심 비즈니스 로직에 집중하고, 트랜잭션 관리와 같은 부가적인 기능은 Spring Framework에 맡기는 것이 가능해집니다. 이는 코드의 가독성과 유지 보수성을 크게 향상시킵니다.

Q.

스프링의 핵심 트랜잭션 기술에 대해 알려줘

 

A.

스프링의 핵심 트랜잭션 관리 기술은 프로그래밍 모델과 구성 모델에 걸쳐 일관성을 유지하면서 다양한 트랜잭션 관리 API를 지원하는 능력에 중점을 둡니다. 

이 중요한 특징은 다음과 같습니다:

1. 플랫폼 트랜잭션 매니저 (PlatformTransactionManager): 스프링은 플랫폼 트랜잭션 매니저라는 추상화 계층을 제공합니다. 이는 JDBC, JTA, Hibernate, JPA 등 다양한 트랜잭션 API에 대한 일관된 프로그래밍 모델을 제공합니다.

2. 선언적 트랜잭션 관리: `@Transactional` 어노테이션을 사용하면, 선언적으로 트랜잭션 범위를 관리할 수 있습니다. 이 어노테이션을 메서드에 적용하면, 해당 메서드는 트랜잭션 범위에서 실행됩니다. 선언적 트랜잭션 관리는 AOP를 기반으로 하며, 코드에서 트랜잭션 관리 로직을 분리하여 코드의 가독성과 유지 보수성을 향상시킵니다.

3. 프로그래밍적 트랜잭션 관리: 선언적 트랜잭션 관리가 적합하지 않은 경우에는, 스프링은 `TransactionTemplate` 클래스를 통해 프로그래밍적 트랜잭션 관리를 지원합니다. 이를 사용하면 코드 내에서 직접 트랜잭션의 시작과 종료를 제어할 수 있습니다.

4. 다양한 트랜잭션 속성: 스프링은 트랜잭션의 격리 수준, 전파 설정, 읽기 전용 설정, 타임아웃 설정 등 다양한 트랜잭션 속성을 제공합니다. 이를 통해 복잡한 트랜잭션 요구 사항을 처리할 수 있습니다.

이처럼 스프링의 핵심 트랜잭션 기술은 다양한 트랜잭션 API를 지원하면서도 일관된 프로그래밍 모델을 제공하며, 코드 내 트랜잭션 로직을 최소화하는 데 중점을 둡니다. 이러한 기능은 스프링을 매우 강력하고 유연한 트랜잭션 관리 프레임워크로 만듭니다.

 

트랜잭션(Transaction) 동기화

스프링은 현재 실행 중인 트랜잭션에 자동으로 동기화되는 세션 기능을 제공합니다. 기능은 Hibernate JPA 같은 ORM(Object-Relational Mapping) 프레임워크와 함께 사용될 특히 유용합니다. 트랜잭션 동기화를 사용하면, 현재 스레드의 트랜잭션 생명주기에 따라 세션 생명주기가 자동으로 관리됩니다.

 

트랜잭션(Transaction) 추상화

스프링의 플랫폼 트랜잭션 매니저(PlatformTransactionManager) 인터페이스는 다양한 트랜잭션 관리 API 대한 일관된 프로그래밍 모델을 제공합니다. 이를 통해 JDBC, JTA, Hibernate, JPA 다양한 데이터 액세스 기술을 동일한 방식으로 다룰 있습니다. 이는 개발자가 새로운 기술을 익히는 드는 시간과 노력을 줄여주며, 유지 보수도 용이하게 만듭니다.

 

AOP를 이용한 트랜잭션(Transaction) 분리

스프링은 `@Transactional` 어노테이션을 통해 선언적 트랜잭션 관리를 제공합니다. 어노테이션은 스프링의 AOP 기능을 기반으로 하며, 이를 통해 트랜잭션 관리 로직을 비즈니스 로직으로부터 분리할 있습니다. 이렇게 함으로써 개발자는 핵심 비즈니스 로직에 집중할 있고, 트랜잭션 관리는 스프링 프레임워크에 맡길 있습니다. 이는 코드의 가독성과 유지 보수성을 크게 향상시킵니다.