Spring

@Transactional 세팅 및 사용법

91cm 2018. 7. 29. 22:05

역시 세팅이 가장 어려운거 같다..


개발을 하다 보면 비즈니스 로직을 처리 해야 할때가 있다. 


여러번의 CRUD작업이 일어나면서 에러가 발생해도 데이터의 정합성을 지켜야 할 때가 있다.(원자성)


기존에는 아래와 같은 방식으로 처리했다.(프로그램에 의한 트랜잭션 처리)


하지만 코드도 지져분해지고 타이핑도 많이 해야되는 단점이 있었다.


그리고 무엇보다 좋은 어노테이션이 있는대 굳이 이렇게 긴소스를 반복해서 쓸 필요가 없다.



- 개선전 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Autowired
private DataSourceTransactionManager txManager;
 
 
public void updateBoard(Board param) throws Exception {
        
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = txManager.getTransaction(def);
        
        try{
            sqlSession.insert("insertaaaaaaaa", param);
            sqlSession.update("updatebbbbbbbb", param);
        } catch (Exception ex) {
            txManager.rollback(status);
            throw ex;
        } finally{
            txManager.commit(status);
        }
    }        
cs









@Transactional (선언적 트랜잭션)


- RuntimeException에 대해서만 롤백처리가 가능하다

  (Exception에 대한 설명은 여기 잘 정리되어 있음 http://www.nextree.co.kr/p3239/)


- MySQL일 경우 Inno일때만 트랜잭션이 작동함


- proxy를 사용할 때 반드시 public 메소드에 사용해야 한다


-클래스들이 인터페이스를 사용하는지 확인해야함

 @Transactional 어노테이션 같은경우 Spring AOP를 이용함 , AOP는 기본적으로 Dynamic Proxy를 이용함

 Dynamic Proxy는 인터페이스 기반으로 동작하기 때문에 인터페이스가 없을경우 트랜잭션이 동작하지 않는다.


-인터페이스없이 트랜잭션을 작동시키려면 CGLib Proxy를 사용하면됨(proxy-target-class="true")

ex) <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>






세팅법


프로젝트구조





servelet-context.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc.xsd
                        http://www.springframework.org/schema/cache 
                        http://www.springframework.org/schema/cache/spring-cache.xsd
                        http://www.springframework.org/schema/security 
                        http://www.springframework.org/schema/security/spring-security.xsd  
                        http://www.springframework.org/schema/tx 
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                        ">
   
    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <!-- <resources mapping="/resource/**" location="/resources/"/> -->
    <mvc:resources mapping="/resources/**" location="/resources/"/>
    <mvc:resources mapping="/js/**" location="/js/" />
    <mvc:resources mapping="/css/**" location="/css/" />
    <mvc:resources mapping="/imgages/**" location="/imgages/" />
 
 
    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
    <!-- MultipartResolver 설정 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="100000000" />
        <property name="maxInMemorySize" value="100000000" />
    </bean>
 
     <tx:annotation-driven transaction-manager="transactionManager" />
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
 
    <context:annotation-config/>
    <context:component-scan base-package="domean"/
    
    <mvc:annotation-driven />
    <mvc:default-servlet-handler />
    
</beans>
 
cs


여기서 dataSource는 DBconect의 bean id이다.



service.java

1
2
3
4
5
6
 
public interface MemberService {
 
    public void insertJoinMember(MemberDTO memberInfo) throws SQLException;
        
}
cs


serviceImple.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
@Service
public class MemberServiceImple implements MemberService{
    
    
    @Autowired
    private MemberDAO memberDAO;
 
    
    @Transactional(rollbackFor =Exception.class
    @Override
    public void insertJoinMember(MemberDTO memberInfo) throws SQLException{
        memberDAO.insertJoinMember(memberInfo);
        String memberSeq=null// 에러발생시킴
        memberDAO.insertJoinMemberAuth(memberSeq);
    }
 
}
cs

rollbackFor : 롤백이 수행되어야 하는 예외클래스를 적어준다
그외 속성은 http://soulduse.tistory.com/40에 자세히 나와있다.