추상화하지 않은 기존 코드의 문제점
- 구현 기술에 따라 트랜잭션 사용법이 다름
- 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);
}
}
- 트랜잭션을 유지하려면 트랜잭션의 시작부터 끝까지 같은 데이터베이스 커넥션을 유지해야 함
- 같은 커넥션을 동기화하기 위해서 이전에는 파라미터로 커넥션을 전달하는 방법을 사용
- 이러한 경우 코드가 지저분해지고 커넥션을 파라미터로 넘기는 메서드와 그렇지 않은 메서드를 중복해서 만들어야하는 단점이 있음