spring- transactionManager란?

Hoo-Sung.Lee·2024년 1월 13일
0

Database

목록 보기
5/18
post-thumbnail

TransactionManager에 대해 대략적으로 알고 있지만, 한번 정리해볼 필요가 있어서 이 글을 포스팅하게 되었습니다.

먼저 Spring에서 사용할 수 있는 DB접근 기술에는 순수 JDBC, JPA등 다양한 기술이 있습니다. 그런데 각각의 기술들은 서로 다른 Transaction 처리 방법을 제공합니다. 아래는 JDBC와 JPA의 차이점을 보여주는 예시입니다.

순수 JDBC의 Transaction

Connection con = dataSource.getConnection();
try {
    con.setAutoCommit(false);//트랜잭션 시작
    //비즈니스 로직
    bizLogic(con, fromId, toId, money);
    con.commit(); //성공시 커밋
} catch (Exception e) {
    con.rollback(); //실패시 롤백
    throw new IllegalStateException(e);
} finally {
    release(con); // connection 릴리즈
}

JPA의 Transaction

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();// Transaction 시작

bizLogic()

transaction.commit();//Transaction 커밋

살짝만 보아도 두 기술의 Transaction을 처리하는 코드가 다르다는 것을 알 수 있습니다. 만약 순수 JDBC를 사용하다가 JPA를 도입하게 된다면, 개발자는 Transaction을 사용하는 코드를 모두 수정해야 하는 골치아픈 상황에 마주하게 됩니다.

이런 상황에서 객체지향적으로 해결하기 위해 Spring은 TransactionManager라는 인터페이스를 통해 트랜잭션을 추상화합니다.

스프링은 트랜잭션을 추상화해서 제공할 뿐 아니라, 실무에서 주로 사용하는 데이터 접근 기술에 대한 트랜잭션 매니저의 구현체도 제공합니다.
심지어 스프링 부트는 어떤 데이터 접근 기술을 사용하는지를 자동으로 인식해서 적절한 트랜잭션 매니저를 선택해서 스프링 빈으로 등록해주기 때문에 트랜잭션 매니저를 선택하고 등록하는 과정도 생략할 수 있습니다.

동작 방식
TransactionManager를 생각하면, DataSource와 TransactionSynchronizationManager를 기억해야 합니다.

DataSource
Spring에서는 기본적으로 Connection Pool을 이용해서 DB Connection을 관리합니다. Transaction도 Connection을 사용해서 이뤄지기 때문에, TransactionManager는 DataSource(Connection Pool)참조를 가지고 있습니다.

TransactionSynchronizationManager
Transaction은 Connection 단위로 이뤄지게 됩니다. 때문에 하나의 요청에 같은 Connection을 사용할 수 있도록 보장해 줘야 하는데, 이 때 사용되는 것이 TransactionSynchronizationManager입니다.

예를 들어, 은행에서 송금하는 로직이 있다고 가정해보자. 단순하게 보면 아래와 같은 3번의 작업이 일어난다고 볼 수 있다.
1. 송금자의 은행에서 잔고 읽어오기
2. 송금자 잔고 업데이트
3. 수신자의 잔고 업데이트

이 때 총 3번의 DB 접근이 일어나고 이 과정은 Atomic 해야 한다. 그런데 이 3번의 접근을 하나의 Connection, 즉, 하나의 Transaction이 아닌 여러 개의 Transaction으로 처리하게 된다면 예상치 못한 상황이 발생할 수 있다.

이를 해결하기 위해 TransactionSynchronizationManager는 ThreadLocal에 Connection을 저장해두고, DB에 접근할 때마다 동일한 Connection을 사용할 수 있도록 보장합니다.

전체적인 과정은 아래와 같습니다.

  1. Transaction 시작
  2. DataSource에서 Connection 획득
  3. Connection을 TransactionSynchronizationManager의 ThreadLocal에 저장
  4. Repository에서 TransactionSynchronizationManager를 통해 Connection 획득 후 처리
  5. 로직 수행 완료
  6. Transaction commit | rollback
  7. TransactionSynchronizationManager의 ThreadLocal에서 Connection 제거
  8. DataSource에 Connection 반환
profile
Working towards becoming Backend-Developer

0개의 댓글