일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- git
- kafka
- 디자인패턴
- 페이스북 번역
- GCM 번역
- graphql
- php
- nginx설정
- APNS
- ddd
- JPA
- Push
- 웹사이트최적화기법
- 카프카 트랜잭션
- nginx
- 도메인 주도 개발
- 웹사이트 성능
- GCM
- 카프카
- 자바스크립트
- gcm 푸시 번역
- 웹사이트성능
- nginx설치
- 푸시 번역
- Java
- notification
- 성능
- Design Pattern
- 푸시
- Today
- Total
간단한 개발관련 내용
[Spring] spring transaction 설정. 본문
Spring4 + myBatis 환경에서 트랜잭션 설정하기.
트랜잭션 위주로 정리해 봅니다. mybatis 는 뭐 정보가 많으니 패스하겠습니다.
1. 기본 설정.
transaction 범위와 관련하여, dispatch-servlet 에서와 applicaitonContext.xml 에서의 component-scan 설정을 수정해 줘야 합니다.
mvc-config.xml
<context:component-scan base-package="com.slowstarter" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
applicationContext.xml
<context:component-scan base-package="com. slowstarter">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
poll(dbcp2, c3po), mybatis 등 필요한 dependency 설정들 추가하기.
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.1</version>
</dependency>
2. aop 를 통한 설정.
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="pushDataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" mode="proxy"/>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="createTest"
isolation="REPEATABLE_READ"
propagation="REQUIRED"
rollback-for"RuntimeException" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="servicePublicMethod"
expression="execution(* com.joochang.service.*Service.*(..))" />
<aop:adviser id="transactionAdvisor"
pointcut-ref="servicePubicMethod" advice-ref="txAdvice" />
</aop:config>
- 스프링AOP 대신 AspectJ-AOP를 사용하는 방법도 있다. AspectJ는 프록시 대신 클래스 바이트코드를 직접 변경해서 부가기능을 추가하기 때문에 타깃 오브젝트의 자기 호출 중에도 트랜잭션 부가기능이 잘 적용된다. 굳이 자신의 메소드를 호출하는 경우에도 트랜잭션 속성이 정확히 적용되기를 원한다면 AspectJ를 사용하는편이 좋다. <tx:annotation-driven mode="aspectj" /> 처럼 설정하면 된다. (Spring AOP 는 기본적으로 JDK프록시이고, AspectJ는 클래스기반 프록시)
3. annotation 을 통한 설정.
MySql 은 기본 isolation 이 repeatable_read 인데, spring 의 default 가 알아서 맞춰주는지 알아볼 필요도 있고 명확하게 해당 타입을 지정해 주는게 더 와 닿는 것 같습니다.
@Transactional(propagation = Propagarion.REQUIRED,
isolation = Isolation.REPEATABLE_READ,
rollbackFor = RuntimeException.class)
public MyTestResult createTest() throws RuntimeException {
...
}
선언적 트랜잭션에서는 런타입 예외가 발생하면 롤백합니다. 반면에 예외가 전혀 발생하지 않거나 checked-exception이 발생하면 commit 합니다. 스프링에서 data-access-exception은 Runtime-Exception으로 전환돼서 던져지므로 Runtime-Exception만 롤백대상이 됩니다. 하지만 롤백대상으로 삼아야 한다면 rollbackFor 를 사용해서 등록합니다. 반대로 기본적인 롤백대상인 Runtime-Exception을 트랜잭션 커밋 대상으로 해 주려면 noRollbackFor 를 사용하면 됩니다.
그리고 rollback 시 createTest() 에서 만약 try catch 쓸 경우 statement 안에서 예외를 잡더라도 throw new RuntimeException 하지 않으면 롤백되지 않습니다. 또한 finally 로 뭔가 동작을 하길 바래서 사용한다면 ㅠㅠ rollback 이 되지 않습니다.
4. 기타 사항.
스프링의 Proxy 는 2가지 타입이 있습니다. JDK Reflection API 를 사용한 JDK다이내믹프록시 와 CBLIB(Code Generator Library) 인데요. JDK프록시는 인터페이스를 구현한 클래스에 적용이되고, CBLIB은 spring 3.2부터 기본적용이 되어있어서 인터페이스를 사용하지 않은 클래스에 대해 적용이 됩니다.
스프링AOP는 기본적으로 JDK Reflection API를 사용하여 Spring에 의해 생성 된 다이내믹 프록시 기법을 이용해 동작합니다. 다이내믹 프록시를 적용하려면 인터페이스가 있어야 하지만 스프링 내부의 ProxyFactoryBean 클래스나 CGLIB 라이브러리가 제공해주는 클래스 레벨의 프록시도 사용할 수 있습니다. AspectJ를 사용해 트랜잭션을 적용할 때는 앞에서 설명한 것처럼 @Transactional을 클래스레벨과 클래스 메소드 레벨에 부여해야 한다는 점을 주의해야합니다. AspectJ 모드를 사용하면서 인터페이스에만 @Transactional을 부여하면 트랜잭션이 적용되지 않습니다. 그래서 클래스프록시 모드에서는 Service 코드에 인터페이스를 Implements 해야한다는니 이런 거 필요없습니다.
명확하게 CGLIB을 사용하려면 proxy-target-class=true 옵션을 아래의 설정에 추가 해야만 합니다.
<tx:annotation-driven proxy-target-class="true">
또는 <aop:config proxy-targer-class="true"> </aop:config>
또는 <aop:aspectj-autoproxy proxy-target-class="true"> // aspectj는 기본이 클래스모드
또는 @EnableAspectJAutoProxy(proxyTargetClass=true)
또는 spring.aop.proxy-target-class=true // application.properties