상품 공급 시스템 - 회원 관련 기능

Connection 객체 관리

JDBC를 사용하여 애플리케이션을 구현하던 중 트랜잭션이 필요하게 되었다. 회원 가입 API는 데이터를 member 테이블과 role 테이블에 정보를 저장하기 때문이다. JDBC에서 트랜잭션을 시작하기 위해서는 Connection 객체의 setAutoCommit(flase)를 호출해야 하는데 트랜잭션을 관리하는 서비스 객체에서 Connection 객체에 접근하는 것은 피하고 싶었다. 서비스 객체에서는 깔끔하게 비즈니스 로직만을 남겨두고 싶었기 때문이다. 서비스 객체가 구체적인 Connection 객체에 의존하게 된다면 JDBCTemplate이나 JPA로의 리팩토링에 드는 비용이 커진다. 이런 이유들 때문에 서비스 객체에서 Connection 객체에 접근하고 싶지 않았다.

스프링에서는 트랜잭션을 관리하는 방식으로서 두 가지 트랜잭션 관리 모델을 제공한다. 첫 번째는 programmatic transaction management이고 두 번째는 declarative transaction management이다. 둘 중 권장되고 더 많이 사용되는 것은 선언적 트랜잭션 관리(declarative transaction management) 방식이다.

자세한 내용은 여기 참고

선언적 트랜잭션 관리

선언적 트랜잭션 관리 방식을 사용하면 트랜잭션을 설정파일로 관리할 수 있어 서비스 코드와 트랜잭션 관리 코드를 분리할 수 있다. 그 이유는 선언적 트랜잭션 관리가 Spring AOP로 구현되어 있기 때문이다. 트랜잭션 프록시가 수행하는 advice를 자유롭게 추가할 수 있다는 점도 장점 중 하나이다.

Configuration file

선언적 트랜잭션 관리 기능을 이용하기 위해서는 xml 또는 Java 설정 파일을 통해 스프링에게 필요한 정보를 전달해야 한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/tranche?serverTime=UTC" />
        <property name="username" value="root" />
    </bean>

    <!-- the PlatformTransactionManager -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- the transactional advice-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- the transactional semantics -->
        <tx:attributes>
            <!-- default transaction settings -->
            <tx:method name="signup" rollback-for="com.example.tranche.domain.member.exception.RecordInsertionFailedException"/>
        </tx:attributes>
    </tx:advice>

    <!-- ensure that the above transactional advice runs for signup method -->
    <aop:config>
        <aop:pointcut id="signupOperation" expression="execution(* com.example.tranche.domain.member.service.SignupService.signup(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="signupOperation" />
    </aop:config>

</beans>

reference

[Spring.io] Transaction Management

Comments