@Transactional 세팅 및 사용법
역시 세팅이 가장 어려운거 같다..
개발을 하다 보면 비즈니스 로직을 처리 해야 할때가 있다.
여러번의 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 |
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 |