본문 바로가기
  • 실행력이 모든걸 결정한다
Spring Series/Spring Framework

[Spring] 트랜잭션 추상화

by 김코더 김주역 2022. 3. 27.
반응형

트랜잭션의 기본 개념을 설명한 포스팅을 첨부했으니 필요하다면 참고하길 바란다.

https://kimcoder.tistory.com/242

 

[Spring] JDBC 트랜잭션

1. 개념 트랜잭션의 개념을 이해하기 전에 COMMIT과 ROLLBACK이 무엇인지 알 필요가 있다. COMMIT : 변경된 내용을 모두 영구적으로 저장하는 명령어 ROLLBACK : 문제가 발생 했을 때, 이전에 COMMIT 했던 시

kimcoder.tistory.com

 

1. 트랜잭션 추상화란?

- 트랜잭션 추상화는 JDBC, JTA, Hibernate, JPA 등과 같이 트랜잭션의 개념을 갖는 여러 기술들에 독립적인 구조를 가지게 하기 위한 방법이다. 즉, 트랜잭션 기술의 공통점을 담은 것이다.

- 아래 그림처럼 트랜잭션 기술마다 트랜잭션의 관리 코드는 달라진다.

- 스프링의 트랜잭션 추상화 기술은 트랜잭션 동기화를 사용한다.

※ 트랜잭션 동기화 : 트랜잭션을 트랜잭션 저장소에서 관리하는 것

 

소스 코드

PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);

public void transactionTask() {
    TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()); // DB Connection도 같이 가져온다.
    try {
        // DB 작업들
        transactionManager.commit(status);
    } catch (RuntimeException e) {
        transactionManager.rollback(status);
        throw e;
    }
}

- PlatformTransactionManager : 트랜잭션 기술들에 대한 추상 인터페이스다. 해당 구현체는 싱글톤으로 사용할 수 있으며, 해당 구현체로 시작한 트랜잭션은 트랜잭션 동기화 저장소에 저장된다.

- TransactionDefinition : 트랜잭션의 속성을 담은 클래스

- TransactionStatus : 트랜잭션의 상태를 담은 클래스로, 현재 진행 중인 트랜잭션을 조회하는 용도로도 유용하게 사용된다.

 

DI 원칙을 따른 소스 코드

위의 소스 코드는 정상적으로 작동은 하지만 이해를 돕기 위한 코드다. 트랜잭션 기술을 바꿔야 하는 경우에는 DataSourceTransactionManager이 아닌 다른 구현체로 바꿔줘야 하기 때문에 이 과정에 소스 코드의 수정이 발생한다. 그래서 수정에는 폐쇄적인 DI 원칙을 따르도록 소스 코드를 바꿔보았다.

private PlatformTransactionManager transactionManager;

// 어느 PlatformTransactionManager의 구현체를 사용할 것인지는 외부에서 결정한다.
public void setTransactionManager(PlatformTransactionManager transactionManager) {
    this.transactionManager = transactionManager;
}

public void transactionTask() {
    TransactionStatus status = this.transactionManager.getTransaction(new DefaultTransactionDefinition()); // DB Connection도 같이 가져온다.
    try {
        // DB 작업들
        this.transactionManager.commit(status);
    } catch (RuntimeException e) {
        this.transactionManager.rollback(status);
        throw e;
    }
}

- PlatformTransactionManager의 구현체는 DataSource 오브젝트를 필요로 하기 때문에 설정 파일에서 주입해주면 된다. 아래 설정은 DataSourceTransactionManager을 사용하는 transactionManager bean을 생성하는 부분이다.

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

※ JtaTransactionManager을 사용하는 경우에는 DataSource와 직접 연동하지 않아도 되지만 서버가 제공해주는 것을 사용해야 한다.

 

 

 

2. PlatformTransactionManager의 구현 클래스

- 2개 이상의 DB를 완전히 독립적으로 사용하지 않는 한, 트랜잭션 매니저는 하나만 등록되어야 한다. DAO는 하나의 클래스로 여러 개의 bean을 생성할 수 있지만, DataSource와 PlatformTransactionManager은 기본적으로 DB별로 하나씩만 등록한다.

 

1) DataSourceTransactionManager

- JDBC에서 사용될 수 있다.

- Connection의 트랜잭션 API를 이용하여 트랜잭션을 관리해준다.

- DataSource는 getConnection()이 호출될 때마다 새로운 Connection을 반환하는데, TransactionAwareDataSourceProxy를 이용하면 현재 진행 중인 트랜잭션이 담긴 Connection을 반환받을 수 있다.

<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    <property name="baseDataSource" ref="baseDataSource" />
</bean>

<bean id="baseDataSource" class="...DataSource">
    ...
</bean>

※ baseDataSource bean에 DB 연결정보가 들어간다.

- DataSourceUtil의 getConnection()은 애플리케이션 코드에서 트랜잭션 매니저가 관리하는 Connection을 반환한다.

- 서버가 제공하는 DataSource와 트랜잭션 서비스를 JNDI로 접근해서 사용할 수 없고, 하나 이상의 DB에 대한 작업을 트랜잭션으로 묶어서 사용할 수 없다. 이 둘을 실현하려면 JTA를 써야 한다.

- 동일한 DataSource를 사용한다면 iBatis를 함께 사용할 수 있다. DataSource로부터 Connection 정보를 가져와서 같은 DataSource를 사용하는 JDBC DAO와 iBatis DAO에 트랜잭션 동기화를 제공하는 것이다.

 

 

2) JpaTransactionManager

- JPA에서 사용될 수 있다.

- DataSourceTransactionManager가 제공하는 DataSource 레벨의 트랜잭션 관리 기능도 제공하기 때문에, 트랜잭션이 적용된 JDBC DAO와 사용할 수도 있다.

- Bean 등록 방법은 https://kimcoder.tistory.com/472의 2번 제목을 참고하면 된다.

- 동일한 DataSource를 사용한다면 JDBC와 iBatis를 함께 사용할 수 있다. JPA가 사용하는 트랜잭션을 JDBC DAO와 iBatis DAO에 동기화해주는 것이다. 

 

 

3) HibernateTransactionManager

- Hibernate에서 사용될 수 있다.

- Bean 등록 방법은 https://kimcoder.tistory.com/475의 2번 제목의 3)-(1)을 참고하면 된다.

- SessionFactory에 적용되어 있는 DataSource와 동일한 DataSource를 사용한다면 JDBC와 iBatis를 함께 사용할 수 있다.

 

 

4) JtaTransactionManager

- 하나 이상의 DB나 트랜잭션 리소스(DB, JMS 등)가 참여하는 글로벌 트랜잭션에 사용될 수 있다. 이 경우에도 트랜잭션 매니저는 JtaTransactionManager 하나만 등록하면 된다.

- 여러 대의 서버에 분산되어 진행되는 작업을 트랜잭션으로 묶을 수도 있다. 물론, 해당 서버나 프레임워크에서는 트랜잭션 서비스가 제공되어야 한다.

- Bean 등록 방법은 https://kimcoder.tistory.com/475의 2번 제목의 3)-(2)를 참고하면 된다. DataSource bean의 경우에는 서버에 등록되어 있는 XADataSource를 참조해서 직접 생성하면 된다.

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myXADataSource" />

- JTA와 분산/글로벌 트랜잭션을 사용하기 위한 설정은 자바 서버마다 다르므로 해당 서버의 매뉴얼을 참고해야 한다.

- WAS의 지원 없이도 애플리케이션 안에 JTA 기능을 내장하는 독립형 JTA 방식도 존재한다.

※ 독립형 JTA 트랜잭션 매니저로는 대표적으로 JOTM, Atomikos가 있다.

 

 

5) JmsTransactionManager, CciTransactionManager

- JMS, CCI에서 사용될 수 있다.

 

 

 

● 참고 자료 : 토비의 스프링 3.1

 

 

반응형

댓글