인터넷에 나와있는 각종 설정을 해봐도 안될경우 다음을 참조하면서 점검해보자
1. 메서드가 public 인지 확인
- private 면 걸리지 않는다
public class TranService() {
@Transactional
private void test1() { // public 으로 변경
...
}
}
2. 한 클래스 내 @Transactional 이 설정되어 있지 않은 메서드에서 @Transactional 이 설정된 메서드를 호출할 경우.
코드 예)
public class TranService() {
public void test1() {
test2();
}
@Transactional
public void test2() {
...
}
}
수정하려면 두가지 방법이 있다
1) 트랜잭션을 호출하는 메서드에 @Transactional 설정(하위는 제거해도 무방)
2) Class 또는 Bean 을 분리
예1)
public class TranService() {
@Transactional
public void test1() {
test2();
}
public void test2() {
...
}
}
예2)
public class TranService() {
@Autowired
private TranTestService tranTestService;
public void test1() {
tranTestService.test2();
}
}
public class TranTestService() {
@Transactional
public void test2() {
...
}
}
2번과 같은 상황이 발생하는 이유
일부로 Exception을 내본 후 트랜잭션 상태를 살펴보면 다음과 같은 에러가 발생해 있다.
(IntelliJ 에서 디버그 모드로 실행)
TransactionAspectSupport.currentTransactionStatus() = NoTransactionException ...
그래서 로그를 살펴보면 다음과 같은 에러가 발생해 있다.
org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope
at org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus(TransactionAspectSupport.java:122)
@Transactional 는 Proxy 기반이고 AOP로 구성되어 있다. 이는 Method 혹은 Class가 실행되기 전/후 등의 단계에서 자동으로 트랜잭션을 묶는다는 의미다.
스프링에서의 @Transactional 은 인스턴스에서 처음으로 호출하는 메서드나 클래스의 속성을 따라가게 된다. 그래서 동일한 Bean안에 상위 메서드가 @Transactional 가 없으면 하위에는 선언이 되었다 해도 전이되지 않는다.
때문에 별도의 클래스(또는 Bean)으로 분리하거나 아니면 상위 메서드에 @Transactional 을 걸어주어야 한다. 이때 하위 메서드에 @Transactional 은 생략해도 된다.
3. TransactionManager에 ProxyDataSource 를 등록했는지 확인
대부분 transactionManager 를 다음과 같이 등록할 것이다
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceMySQL" />
</bean>
위 설정에서 ref 에 보이는 dataSourceMySQL 의 Bean 은 Log4jdbcProxyDataSource 를 구현한 것이다.
만약 ref에 다가 dataSource 를 넣으면 @Transactional 이 작동하지 않는다
(@Transactional 은 Proxy 기반이기 때문)
해서 다음과 같이 transactionManager 와 ProxyDataSource 를 한 쌍으로 등록되었는지 확인한다.
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceMySQL" />
</bean>
<bean id="dataSourceMySQL" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
<constructor-arg ref="dataSource" />
<property name="logFormatter">
<bean class="net.sf.log4jdbc.tools.Log4JdbcCustomFormatter">
<property name="loggingType" value="MULTI_LINE" />
<property name="sqlPrefix" value="" />
</bean>
</property>
</bean>
끝.
참조사이트:
https://netframework.tistory.com/entry/Spring-Transactional에-대하여
'공부 > 프로그래밍' 카테고리의 다른 글
[gradle] build 실패(No cached version of available for offline mode) (0) | 2019.08.27 |
---|---|
[jenkins] Execute Shell 에서 프로세스 이름으로 프로세스 kill 하기 (0) | 2019.08.22 |
[JPA] DataSource 사용자설정 및 @DataJpaTest 테스트 (0) | 2019.08.04 |
[shell] 프로세스 실행 중 확인 (ps 명령어) (0) | 2019.07.31 |
[jenkins] 에러로그 Disk Full(DNSQuestion) (0) | 2019.07.28 |
댓글