추상화하지 않은 기존 코드의 문제점

  • 구현 기술에 따라 트랜잭션 사용법이 다름
    • JDBC : con.setAutoCommit(false)
    • JPA : transaction.begin()
  • 만약 JDBC 기술을 사용하다가 JPA로 변경하면 서비스 계층의 코드도 JPA의 기술에 맞게 수정해야 함

인터페이스를 활용한 트랜잭션 추상화

public interface TxManager { 
    begin(); 
    commit(); 
    rollback(); 
}
  • 위와 같이 TxManager인터페이스를 기반으로 각각의 기술에 맞는 구현체를 만들면 된다
    • JdbcTxManager : JDBC 트랜잭션 기능을 제공하는 구현체
    • JpaTxManager : JPA 트랜잭션 기능을 제공하는 구현체

  • 서비스 계층은 이제 특정 트랜잭션 기술에 직접 의존하는 것이 아니라, TxManager라는 인터페이스에 의존한다
  • 필요한 구현체는 DI를 통해 주입하면 된다
  • 클라이언트인 서비스 계층은 인터페이스에 의존하고 DI를 적용한 덕분에 OCP 원칙을 지키가 되었다. 이제 트랜잭션을 사용하는 서비스 클래스의 코드를 전혀 변경하지 않고, 트랜잭션 기술을 쉽게 변경할 수 있다.

스프링이 제공하는 트랜잭션 추상화

  • 스프링 트랜잭션 추상화의 핵심은 PlatformTransactionManager 인터페이스다

PlatformTransactionManager 인터페이스

package org.springframework.transaction; 

public interface PlatformTransactionManager extends TransactionManager {

TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException; 
void rollback(TransactionStatus status) throws TransactionException; 

}
  • getTransaction() : 트랜잭션을 시작
    • 이름이 getTransaction()인 이유는 기존에 이미 진행중인 트랜잭션이 있는 경우, 해당 트랜잭션에 참여할 수 있기 때문
  • commit() : 트랜잭션 커밋
  • rollback() 트랜잭션 롤백

리소스 동기화를 위해 적용한 기존 코드의 문제점

public class MemberRepositoryV2 {  

    private final DataSource dataSource;  

    public MemberRepositoryV2(DataSource dataSource) {  
        this.dataSource = dataSource;  
    }  

    public Member findById(String memberId) throws SQLException { ... }  

    public Member findById(Connection con, String memberId) throws SQLException { ... }  

    public void update(String memberId, int money) throws SQLException { ... }  

    public void update(Connection con, String memberId, int money) throws SQLException { ... }  

    private Connection getConnection() throws SQLException {  
        Connection conn = dataSource.getConnection();  
        log.info("conn = {}, conn.class = {}", conn, conn.getClass());  
        return conn;  
    }  

    private void close(Connection con, Statement stmt, ResultSet rs) throws SQLException {  
        JdbcUtils.closeResultSet(rs);  
        JdbcUtils.closeStatement(stmt);  
        JdbcUtils.closeConnection(con);  
    }  
}
  • 트랜잭션을 유지하려면 트랜잭션의 시작부터 끝까지 같은 데이터베이스 커넥션을 유지해야 함
  • 같은 커넥션을 동기화하기 위해서 이전에는 파라미터로 커넥션을 전달하는 방법을 사용
  • 이러한 경우 코드가 지저분해지고 커넥션을 파라미터로 넘기는 메서드와 그렇지 않은 메서드를 중복해서 만들어야하는 단점이 있음

+ Recent posts