Java로 웹 개발을 할때 Spring 프레임워크를 빼놓고 얘기하면 거의 빈 껍데기 혹은 어불성설 같은 느낌일 겁니다. 그만큼 보편화 되어 있는데, 이걸 논할때 트랜잭션 개념을 빼면 겉핧기식으로 공부했다고 보는 것 같아요. 그래서 정리하려고 합니다.

 

1.  트랜잭션 개념

Spring MVC - 트랜잭션이란 도데체 뭐란 말인가!

자세한 설명은 위 블로그 글에 잘 나와 있네요. 구글링을 좀 했는데, 다들 보시면 좋을 거 같습니다.

대신, 요약을 하면

하나의 쿼리에 대한 commit/rollback을 넘어서, 업무처리같이 단위는 하나지만 그 안에 insert/update/delete (+select) 쿼리 여러개가 순차적으로 모두 에러없이 실행되어야 처리되었다고 말할 수 있을때, 이렇게 안에 세부 순서를 가진 업무 단위 혹은 이를 처리하기 위한 기술을 트랜잭션이라고 부릅니다.

 

2. Java에서 트랜잭션을 처리하는 방법 (혹은 이것의 변화과정)

(1) Procedure

Spring이 등장하기 이전에, 혹은 MVC 개념이 발전하기 전엔 DB에서 프로시저를 작성하고 그 안에 쿼리들을 넣어서 트랜잭션을 처리하게 했다고 합니다. 단점은 DB를 바꿀때, 예를 들어 mysql에서 oracle로 바꾼다 그러면 DBA는 죽어나는거죠. 아마 이때쯤에 DB 튜닝 혹은 쿼리 튜닝 일하시는 분들 단가가 엄청 올라갔던거 같습니다. 그리고 오라클 같은 경우는 패키지라고 해서 프로시저를 묶은 개념이 있더라고요. 업무차 두세번 정도 작업 했었는데, 문법 차이만 있지 작성 방법은 비슷했었습니다.

(2) 메소드 내 try ~ catch ~ finally 구문에서 여러 쿼리 호출

개발자 입장에서 트랜잭션을 구현한다고 했을때 쉽게 떠오르는 방식일거 같네요. 우선은 connection 객체에서 setAutoCommit(false) 로 자동 커밋을 막고, 쿼리 여러개를 쭉 수행한 다음 try ~ catch 사이 마지막에 commit() 을 호출하는 겁니다. 문제는 소스코드에서 중복되는 부분이 너무 많다는 거겠죠. 개발자들에게도 스트레스가 될거고요.

(3) Spring 에서 처리하기

스프링에서는 크게 AOP와 어노테이션으로 트랜잭션을 구현할 수 있습니다.

우선 AOP를 이용한 방식입니다.

// mvc-config.xml
<context:component-scan base-package="com.kevins.web" use-default-filters="false">
  <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

// application-config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"    // 추가할 부분
       xmlns:tx="http://www.springframework.org/schema/tx"      // 추가할 부분
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop                       // 추가할 부분
                           http://www.springframework.org/schema/aop/spring-aop.xsd        // 추가할 부분
                           http://www.springframework.org/schema/tx                        // 추가할 부분
                           http://www.springframework.org/schema/tx/spring-tx.xsd"         // 추가할 부분
>

...

//추가할 부분
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

<aop:config proxy-target-class="true">
  <aop:pointcut id="serviceOperation" expression="execution(public * com.kevins.web..service.*Service.*(..))" />
  <aop:advisor id="transactionAdvisor" pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
</aop:config>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
    <tx:method name="save*" rollback-for="Exception"/>
    <tx:method name="update*" rollback-for="Exception"/>
    <tx:method name="remove*" rollback-for="Exception"/>
  </tx:attributes>
</tx:advice>

...

</beans>

이렇게 Spring 설정을 해놓으면 Controller/Service/DAO를 구현하고, DAO내 메소드 명을 <tx:method> 태그 부분에 선언한대로만 맞추면 자동으로 실행되는거 같습니다. 대신 DAO 선언시 @Repository 어노태이션을 꼭 붙일것과, AOP 설정을 잘 이해해야겠죠.

어노테이션으로 구현하는 것은 AOP보다 쉽다고 합니다. Service\DAO 구현체나 그 메소드 앞에 @Transactional 이라는 어노테이션을 붙이면 되네요. 대신에 dataSource 설정하는 스프링 설정파일에 transactionManager 까지는 선언되어있어야 합니다.

그리고 프로그램적 선언 방식도 있다고 하는데 설정파일에 선언한 transactionManager를 @Resource 어노테이션으로 직접 호출해서 commit/rollback을 제어하는 방식입니다.

 

3. 마무으리

급하게 정리하다보니 다른 블로그를 많이 참고했습니다. 참고한 블로그 목록 입니다. 정리가 훨씬 잘 되어 있으므로 가급적 참고하시길 바랍니다.

Outsider's Dev Story - [Spring 레퍼런스] 11장 트랜잭션 관리 #1

가리사니 - Spring @Transactional Method 적용범위 : rollback 주의

박철우의 블로그 - 스프링의 트랜잭션 관리

성일만 - [Spring] 스프링 트랜잭션 적용하기 (Spring + MyBatis + MySQL)

Full Stack Web Developer Syaku - #5 스프링 트랜잭션 - 스프링 프레임워크 게시판 : Spring Framework Transaction

 

Posted by kevin.jeong.
,