스프링에선 트랜젝션을 관리하기 위해 여러방법이 있지만,

필자가 사용한 방식 중 가장 편한 방식으로 AOP를 이용한 선언적 트랜젝션을 셋팅을 해보겠다.

 

이 방식은 서버스에 선언한 메소드명으로 읽기 전용인지, 트랜젝션을 적용할지 정할 수 있다.

 

먼저 pom.xml 파일에 dependency를 추가하자.

 

 

<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.8.1</version>
  </dependency> 

 

 

 

다음으로 applicationContext.xml파일을 수정해보자.

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 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/mvc
   http://www.springframework.org/schema/mvc/spring-mvc.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" >

 

 <mvc:annotation-driven/>

 

 <context:component-scan base-package="com.test.web" />

 

 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
  <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
  <property name="username" value="test"/>
  <property name="password" value="test"/>
 </bean>

 

 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="configLocation" value="/WEB-INF/mybatis-config.xml" />
  <property name="typeAliasesPackage" value="com.test.web" />
  <property name="mapperLocations" value="classpath*:com/test/web/**/dao/mapper/*Mapper.xml" />
 </bean>

 

 <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg ref="sqlSessionFactory" />
 </bean>
 
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
 </bean>
 
 <tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
   <tx:method name="*" rollback-for="Exception"/>
  </tx:attributes>
 </tx:advice>

 

 <aop:config>
  <aop:pointcut id="txPointcut" expression="execution(* com.test.web.*.service.*ServiceImpl.*(..))" />
  <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
 </aop:config>

 

 <!-- dao 스캔 -->
 <bean class= "org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="com.test.web.**.dao" />
 </bean>
 
 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/view/" />
  <property name="suffix" value=".jsp" />
 </bean>

 

</beans> 

 

여기서 중점적으로 보일 부분은 pointcut 부분이다.

 

<aop:pointcut id="txPointcut" expression="execution(* com.test.web.*.service.*ServiceImpl.*(..))" />

 

aop를 사용하여 com.test.web.기능명.service 패키지내 기능명ServiceImpl의 모든 메소드에 대해 트랜잭션을 사용하도록 설정할 것이다.

 

다음으로 아래 부분을 확인해보자.

 

<tx:method name="*" rollback-for="Exception"/>

이 부분은 모든 메소드에서 Exception이 발생하였을 경우 무조건 롤백 하도록 설정하였다.

 

 

그럼 테스트를 해보도록 하자

 

먼저 정상적으로 데이터가 입력되는지 확인해보자.

 

브라우저를 이용하여 이전에 만들어 놓았던 회원 가입 화면을 호출한다.

 

http://localhost/member/insertMemberForm.do

 

데이터는 임의의 데이터를 입력하도록 한다.

 

회원 아이디 : hong2

회원명 : 홍길동2

회원패스워드 : 1234

회원주소 : 서울시 종로구

 

 

회원 가입을 클릭 후 데이터를 확인해보자

 

 


MB_ID                MB_NAME              MB_PW               MB_ADDR               
---------------- ------------------ ----------------- --------------------------------------

hong2                홍길동2                   1234                    서울시 종로구 

hong                  홍길동                    1234                    서울시 종로구

2 rows selected. 

 

MB_ID가 hong2라는 데이터가 정상적으로 입력되었음을 확인할 수 있다.

 

다음으로 소스를 살짝 수정하여 롤백 되는 상황을 살펴 보겠다.

 

MemberServiceImpl 내 insertMember 메소드의 내용 중

 

memberDao.insertMember(memberBean); 호출 후 에러를 발생시켜보자.

 

 

 /** 회원 가입 */
 public int insertMember(MemberBean memberBean) throws Exception {
  memberDao.insertMember(memberBean);
  throw new Exception();
 } 

 

그럼 다시 회원 가입 화면에서 이번엔 hong3 이라는 데이터를 입력 후 회원 가입 버튼 클릭

 

바로 에러 화면이 발생할 것이다.

 

로그를 확인해보자.

 

2015/07/17 19:26 INFO  (MemberController.java:47) - memberBean.mbId : hong3
2015/07/17 19:26 INFO  (MemberController.java:48) - memberBean.mbName : 홍길동3
2015/07/17 19:26 INFO  (MemberController.java:49) - memberBean.mbPw : 1234
2015/07/17 19:26 INFO  (MemberController.java:50) - memberBean.mbAddr : 서울시 종로구
2015/07/17 19:26 DEBUG (JakartaCommonsLoggingImpl.java:27) - ooo Connection Opened
2015/07/17 19:26 DEBUG (JakartaCommonsLoggingImpl.java:27) - ==>  Executing: INSERT INTO TB_MEMBER ( MB_ID, MB_NAME, MB_PW, MB_ADDR ) VALUES ( ?, ?, ?, ? )
2015/07/17 19:26 DEBUG (JakartaCommonsLoggingImpl.java:27) - ==> Parameters: hong3(String), 홍길동3(String), 1234(String), 서울시 종로구(String)
7월 17, 2015 7:26:10 오후 org.apache.catalina.core.StandardWrapperValve invoke
심각: Servlet.service() for servlet [dispatcher] in context with path [] threw exception [Request processing failed; nested exception is java.lang.Exception] with root cause
java.lang.Exception
 at com.test.web.member.service.MemberServiceImpl.insertMember(MemberServiceImpl.java:26) 

 

정상적으로 INSERT 쿼리 로그가 찍힘을 확인할 수 있으며, 다음으로 바로 Excepion이 발생하였다.

 

디비를 확인해보자

 


MB_ID                MB_NAME              MB_PW               MB_ADDR               
---------------- ------------------ ----------------- --------------------------------------

hong2                홍길동2                   1234                    서울시 종로구 

hong                  홍길동                    1234                    서울시 종로구

2 rows selected. 

 

hong3 이란 데이터는 없고, 기존 데이터만 두건 있다.

 

이렇게 정상적으로 트랜젝션이 동작하여, 서비스에서 Exception 발생시 롤백되는 것을 확인할 수 있다.

 

만약 데이터 조회시 hong3 이라는 데이터가 조회된다면, 트랜젝션이 동작하지 않은 것이다.

 
블로그 이미지

애니스

카테고리

분류 전체보기 (10)
프로그래밍 (10)
애니스전용 (0)