Spring Framrwork

Spring Transaction Simulation 기능

gregorio 2020. 3. 3. 08:09

Spring Framework에서 CUD에 Transaction에 대해 DB에 데이터를 저장하지 않고 기능이 

정상적으로 동작하는지 확인이 필요한 경우가 있을 수 있다.

이 때 새로운 User Transaction을 정의한 후 모든 Transaction을 Rollback처리하도록 설정하면 가능하다.

 

본 기능에 대해서는 많은 테스트를 수행하지 않았지만, 하나의 테이블에 대한 Insert에 대해서는 정상적으로 

동작하는것을 테스트하였다.

 

Transaction은 일반적으로 서비스 단위에서 시작하지만,  모든 Trasnsaction을 Rollback 처리하기 위한 User

Transaction을 생성을 어디에서 해야할지 정의해야한다.

 

본 예제에서는 User Transaction을 Interceptor에서 정의한 후 해당 Transaction을 Rollback only로 설정하였다.

 

예제 프로그램은 다음과 같다.

 

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class SimulatorInterceptor extends HandlerInterceptorAdapter implements InitializingBean {

private static final Logger LOGGER = LoggerFactory.getLogger(SimulatorInterceptor.class);
private boolean enabled;
private boolean keyEnabled;
private String key;

private PlatformTransactionManager txManager;


@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

String requestUri = ((HttpServletRequest)request).getRequestURI();

String keyValue = (String)request.getParameter(key);
keyValue = keyValue != null ? keyValue : "N";
if (enabled && (keyEnabled && "Y".equalsIgnoreCase(keyValue))) {
LOGGER.info("This [{}] request is for simulation", requestUri);

DefaultTransactionDefinition transDef = new DefaultTransactionDefinition();
transDef.setName("SimulationTx");
transDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transDef.setReadOnly(false);
transDef.setTimeout(30);
try {
/** New transaction **/
TransactionStatus status = txManager.getTransaction(transDef);
if (status.isNewTransaction()) {
LOGGER.warn("This [{}] transaction is created", requestUri);
}

/** Set roll back only **/
status.setRollbackOnly();
LOGGER.warn("This [{}] request is  roll back only", requestUri);
}
catch(Exception ex) {
LOGGER.error(ex.getMessage());
}

}

return super.preHandle(request, response, handler);
}


@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mav) throws Exception {
SimulatorContextHolder.rollback();
/** Do nothing **/
}


public void setEnabled(boolean enabled) {
this.enabled = enabled;
}


public void setKey(String key) {
this.key = key;
}


public void setKeyEnabled(boolean keyEnabled) {
this.keyEnabled = keyEnabled;
}


public void setTxManager(PlatformTransactionManager txManager) {
this.txManager = txManager;
}


@Override
public void afterPropertiesSet() throws Exception {
if (keyEnabled && key == null) {
this.key = "simulationYn";
}
}
}

1. DefafultTransactionDefinition을 통해 Transaction 이름, Prapagatio, ReadOnly 및 Timeout을 정의한다.

2. TransactionManager를 통해 TransactionStatus를 생성한다.

3. TransactionStatus.setRollbackOnly를 통해 모든 Transaction을 Rollback처리한다.

 

본 예제에서는 Interceptor에서 User Transaction을 REQUIRED로 생성한 후 이후 모든 Transaction이 REQUIRED로

정의되어 있는 경우에 사용이 가능한다.

 

User Transaction 생성 이후 다음 Transaction이 REQUIRED_NEW로 정의되면 정상적으로 모든 Transaction이 Rollback 되지 않는다.